Angular Как передать данные из директивы в родительский компонент - PullRequest
0 голосов
/ 09 апреля 2020

Мое требование примерно такое: у меня есть таблица многоразового использования, которую я хочу использовать в нескольких местах. Я передаю данные таблицы и столбцы, где я использую эту таблицу.

Теперь в некоторых родительских компонентах я хочу получать данные, когда пользователь щелкает строку таблицы или дважды щелкает строку таблицы.

Для этого у меня есть директива, использующая @ HostListener.

Когда я использую директиву для строки таблицы, я могу получить данные строки по щелчку в директиве, но когда я посылаю эти данные, я не получаю их в родительском.

table.component. html

<section class="example-section">

  <div class="cdx-table-wrapper cdx-table-wrapper-fixed">
    <table mat-table [dataSource]="tableData" class="mat-elevation-z8">
      <!--- Note that these columns can be defined in any order.
            The actual rendered columns are set as a property on the row definition" -->

      <ng-container *ngFor="let disCol of tableColumns; let colIndex = index" matColumnDef="{{disCol}}">
        <th mat-header-cell *matHeaderCellDef>{{disCol}}</th>
        <td mat-cell *matCellDef="let element">{{element[disCol]}}</td>
      </ng-container>

      <tr class="persues-table-row" mat-header-row *matHeaderRowDef="tableColumns"></tr>
      <tr class="persues-table-row" mat-row *matRowDef="let row; columns: tableColumns;" appTableEvent [rowData]="row"></tr>
    </table>
  </div>
</section>

table-events.directive.ts

import { Directive, HostListener, Input, Output, EventEmitter } from '@angular/core';

@Directive({
  selector: '[appTableEvent]'
})
export class TableEventDirective {
  @Input() rowData;

  @Output()
  clickHandler: EventEmitter<any> = new EventEmitter();

  constructor() { }

  @HostListener('click', ['$event'])
  onClickHandler(event: MouseEvent) {
    this.clickHandler.emit(this);
  }
}

родительский компонент

<app-table
  [tableData]="dataSourceBase"
  [tableColumns]="displayedColumnsBase"
  (clickHandler)="onRowClick($event)">
</app-table>

родительский компонент ts

onRowClick(event) {
  console.log('onRowClick', event)
}

Я не получаю данные в onRowClick() method.

Теперь есть некоторые случаи, когда я просто хочу использовать таблицу, чтобы просто показывать данные, в этом случае я не хочу применять директиву.

Заранее спасибо

Ответы [ 2 ]

1 голос
/ 09 апреля 2020

Рабочая демонстрация в этом StackBlitz Link

Здесь , вы можете использовать service и rxjs - Behaviorsubject. Для этого вам нужно создать один сервис, а затем в этом сервисе определить свой Behaviorsubject и все общепринятые вещи, связанные с общением. Вы должны внедрить этот сервис в компонент и в директиву. так что вам не нужно @Output() многоуровневое и одно преимущество этого, вы можете общаться с любым родительским уровнем компонента независимо от цепочки событий.

table.component. html

<code><table class="table table-dark table-striped table-hover">
   <thead>
     <tr>
       <th scope="col">ID</th>
       <th scope="col">Company Name</th>
       <th scope="col">Brand</th>
       <th scope="col">Engine Type</th>
     </tr>
   </thead>
   <tbody>
      <tr *ngFor="let row of tableService.tableData; let i = index" appTableRow [rowData]="row">
        <th scope="row">{{row.id}}</th>
        <td>{{row.companyName}}</td>
        <td>{{row.brand}}</td>
        <td>{{row.engineType}}</td>
      </tr>
   </tbody>
</table>

<div *ngIf="selectedRow | async as rowSelect" class="alert alert-primary">
  <pre>
    {{rowSelect | json}}
  

table.component.ts

export class TableComponent implements OnInit {
  selectedRow;
  constructor(private tableService: TableDataService) { }

  ngOnInit() {
    this.selectedRow = this.tableService.getTableRow();
  }
}

directive.ts

@Directive({
  selector: '[appTableRow]'
}) 
export class TableRowDirective {
   @Input() rowData;

   constructor(private tableRowSerivce: TableDataService) { }

   @HostListener('click', ['$event'])
      onClickHandler(event: MouseEvent) {
         this.tableRowSerivce.tableRowData.next(this.rowData);
      }
}

table-service.ts

@Injectable()  
export class TableDataService {

  tableData = [{
   id: 1,
   companyName: 'Audi',
   brand: 'A4',
   engineType: 'Diesel'
  },{
   id: 2,
   companyName: 'Rolls-Roys',
   brand: 'R4',
   engineType: 'Diesel'
  },{
   id: 3,
   companyName: 'Hyundai',
   brand: 'Kona',
   engineType: 'Electric'
  },{
   id: 4,
   companyName: 'Ford',
   brand: 'Endevour',
   engineType: 'Diesel'
 }];

  tableRowData : BehaviorSubject<any> = new BehaviorSubject<any>({});
  tableRowData$ = this.tableRowData.asObservable();

  constructor() { }

  getTableRow(): Observable<any>{
    return this.tableRowData$;
  }
}
1 голос
/ 09 апреля 2020

Вам также необходимо создать HostListener для компонента таблицы:

@Component({
  selector: 'app-table'
})
export class TableComponent {
  @Output()
  clickHandler: EventEmitter<MouseEvent> = new EventEmitter();
}

и получить его из директивы appTableEvent:

<tr class="persues-table-row" mat-row
    *matRowDef="let row; columns: tableColumns;" [rowData]="row"
    appTableEvent (clickHandler)="clickHandler.emit($event)">
</tr>

Если вы планируете иметь несколько таких случаев, вы также можете go для следующего решения. Вам все равно понадобится clickHandler на вашем TableComponent, как я показал ранее, но вы можете обновить свою директиву следующим образом:

@Directive({
  selector: '[appTableEvent]'
})
export class TableEventDirective {
  @Input() rowData;

  constructor(@Host() private table: TableComponent) { }

  @HostListener('click', ['$event'])
  onClickHandler(event: MouseEvent) {
    this.table.clickHandler.emit(this);
  }
}

Таким образом, вам не нужно добавлять обработчик щелчков к <tr> элемент

...