Saltar al contenido

Cómo crear una tabla de tapetes anidada en una tabla con filas expandibles usando material angular

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.

¡Haz clic para puntuar esta entrada!
(Votos: 1 Promedio: 5)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *