Trouble making components reusable in Angular

47 Views Asked by At

I've been trying to make a custom Material Angular Table component reusable. The component will have the ability to expand rows to display a details component.

My first idea was to content project the column definitions and details component into the reusable table via the parent. This is pseudocode btw, dont try to run it.

expansion-table.ts

getRowId(row: any) {
    return row.id;
} 

// Used to determine which order to expand
expanded: string | undefined;
expansion-table.html

<mat-table multiTemplateDataRows [dataSource]="dataSource">

    <ng-content select="[rowColumns]" /> // column definition
    <ng-container [ngClass]={expanded: expanded === getRowId(row)} matColumnDef="expandedDetail"> 
        <ng-content select="[rowDetail]" /> // details component
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedOuterColumns"></tr>
    <tr
      mat-row
      *matRowDef="let row; columns: displayedColumns"
      (click)="
        expandedRow =
          expandedRow === getRowId(row) ? undefined : getRowId(row) 
      "
    ></tr>
    <tr
      mat-row
      *matRowDef="let row; columns: ['expandedDetail']"
    ></tr>

<mat-table>

Then I pass in the column definitions as such

parent.ts

mockDisplayedColumns = ['id', 'name'];

mockData = [
    {
      id: 1,
      name: 'John',
    },
    {
      id: 2,
      name: 'Jane',
    },
    {
      id: 3,
      name: 'Bob',
    },
  ];
parent.html

<app-expansion-table
    [setData]="data"
    [displayedColumns]="displayedColumns"
  >
    <ng-container rowColumns matColumnDef="id">
      <th mat-header-cell *matHeaderCellDef class="col">id</th>
      <td mat-cell *matCellDef="let element">id</td>
    </ng-container>
    <ng-container>
      <app-details [data]="row.details" />
    </ng-container>
</app-expansion-table>

But this resulted in this error:

ERROR Error: Could not find column with id "id".

I suspect the column definitions can't be projected, and that this is not the way to implement this feature. Does anyone have any experience building such reusable components that could point me in the right direction?

1

There are 1 best solutions below

0
Christophe Le Besnerais On

There is a (basic) example for how to wrap a table component for definition and behavior reuse in the official doc : https://material.angular.io/components/table/examples#table-wrapped

Direct link to the stackblitz: https://stackblitz.com/run?file=src%2Fapp%2Ftable-wrapped-example.ts