Solución:
Nota: Para aquellos que quieran omitir la explicación extensa, aquí está el ejemplo de StackBlitz.
Lo que realmente quiere es crear un anidado mat-table
donde todas las tablas anidadas se pueden ordenar y también se pueden filtrar.
En primer lugar, dado que necesita utilizar el filtrado y la ordenación en su tabla anidada, debe crear una nueva MatTableDataSource
para ello. Esto se puede hacer inicialmente cuando crea la dataSource
en el ngOnInit
como abajo.
usersData: User[] = [];
USERS.forEach(user => {
if (user.addresses && Array.isArray(user.addresses) && user.addresses.length) {
this.usersData = [...this.usersData, { ...user, addresses: new MatTableDataSource(user.addresses) }];
} else {
this.usersData = [...this.usersData, user];
}
});
this.dataSource = new MatTableDataSource(this.usersData);
En el ejemplo de filas expandibles en los documentos, podemos ver cómo crear una fila expandible. En la fila expandible, ahora tendremos una tabla junto con el Filter
aporte. Agregaremos algunas condiciones para que la fila sea expandible solo si hay addresses
regalo.
<div class="example-element-detail" *ngIf="element.addresses?.data.length"
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
<div class="inner-table mat-elevation-z8" *ngIf="expandedElement">
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
<table #innerTables mat-table #innerSort="matSort" [dataSource]="element.addresses" matSort>
<ng-container matColumnDef="{{innerColumn}}" *ngFor="let innerColumn of innerDisplayedColumns">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{innerColumn}} </th>
<td mat-cell *matCellDef="let element"> {{element[innerColumn]}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="innerDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: innerDisplayedColumns;"></tr>
</table>
</div>
</div>
Ahora que la fila se expande solo si hay elementos anidados, necesitamos deshacernos del hover para los usuarios que no tienen addresses
Aquí está el CSS responsable de agregar un background-color
en vuelo estacionario
tr.example-element-row:not(.example-expanded-row):hover {
background: #777;
}
Entonces solo necesitamos agregar el example-element-row
clase a nuestra fila si la fila tiene un address
. Si no tiene dirección, no se debe poder hacer clic en la fila y no debe haber un mensaje flotante que indique al usuario que, de hecho, no se puede hacer clic en la fila.
<tr mat-row *matRowDef="let element; columns: columnsToDisplay;"
[class.example-element-row]="element.addresses?.data.length"
[class.example-expanded-row]="expandedElement === element"
(click)="toggleRow(element)">
</tr>
En toggleRow
, definiremos la lógica de lo que sucede cuando hace clic en una fila de la plantilla. También implementaremos sort
cuando el usuario hace clic en la fila de esta función.
@ViewChildren('innerSort') innerSort: QueryList<MatSort>;
toggleRow(element: User) {
element.addresses && (element.addresses as MatTableDataSource<Address>).data.length ? (this.expandedElement = this.expandedElement === element ? null : element) : null;
this.cd.detectChanges();
this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource<Address>).sort = this.innerSort.toArray()[index]);
}
Finalmente, necesitamos definir el applyFilter
función para que las tablas anidadas se puedan filtrar.
@ViewChildren('innerTables') innerTables: QueryList<MatTable<Address>>;
applyFilter(filterValue: string) {
this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource<Address>).filter = filterValue.trim().toLowerCase());
}
Aquí hay un ejemplo de trabajo en StackBlitz.