如何使用角材料在具有可扩展行的表格中创建嵌套垫表 [英] How to create a nested mat-table in a table with expandable rows using angular material

查看:27
本文介绍了如何使用角材料在具有可扩展行的表格中创建嵌套垫表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下数据

[{"_id": "c9d5ab1a","子域": "翼","domain": "飞机","part_id": "c9d5ab1a","info.mimetype": "应用程序/json",信息依赖":父母",嵌套":[{"domain": "飞机","_id": "c1859902","info.mimetype": "图像/jpeg","info.dependent": "c9d5ab1a","part_id": "c1859902",子域":尾巴"}]},{"_id": "1b0b0a26",子域":燃料","domain": "飞机","part_id": "1b0b0a26","info.mimetype": "图像/jpeg","info.dependent": "no_parent"}]

这里如果 "info.dependent": "parent" 那么它是嵌套的,如果 "info.dependent": "no_parent" 那么它没有孩子.我试图创建一个动态表,但我被困在如何使用嵌套表使其可折叠/可扩展.这是我在

嵌套格式如下

<块引用>

第 1 行 --> _id ,subdomain,domain,info.dependent

当我们单击该特定行时,它必须展开并显示带有列名和行数据的表格中的嵌套数据.

嵌套":[{"domain": "飞机","_id": "c1859902","info.mimetype": "图像/jpeg","info.dependent": "c9d5ab1a","part_id": "c1859902",子域":尾巴"}]

解决方案

注意:对于那些想跳过冗长解释的人,这里是 StackBlitz 示例.

您真正想要的是创建一个嵌套的 mat-table,其中所有嵌套的表都是可排序的,也可以过滤.

首先,由于您需要在嵌套表中使用过滤和排序,您需要为其创建一个新的MatTableDataSource.这可以在您在 ngOnInit 中创建主 dataSource 时完成,如下所示.

usersData: User[] = [];USERS.forEach(用户 => {if (user.addresses && Array.isArray(user.addresses) && user.addresses.length) {this.usersData = [...this.usersData, { ...user,addresses: new MatTableDataSource(user.addresses) }];} 别的 {this.usersData = [...this.usersData, user];}});this.dataSource = new MatTableDataSource(this.usersData);

从可扩展行文档中的示例,我们可以看到如何创建一个可扩展行.在可扩展行中,我们现在将有一个表格以及 Filter 输入.我们将添加一些条件,以便仅当存在 addresses 时该行才可展开.

<div class="example-element-detail" *ngIf="element.addresses?.data.length"[@detailExpand]="element == expandElement ? '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="letinnerColumn of innerDisplayedColumns"><th mat-h​​eader-cell *matHeaderCellDef mat-sort-header>{{innerColumn}} </th><td mat-cell *matCellDef="let element">{{element[innerColumn]}} </td></ng-容器><tr mat-h​​eader-row *matHeaderRowDef="innerDisplayedColumns"></tr><tr mat-row *matRowDef="let row; columns:innerDisplayedColumns;"></tr>

既然只有在有嵌套元素时行才会扩展,我们需要为没有addresses

的用户摆脱悬停

这是负责在悬停时添加 background-color 的 CSS

tr.example-element-row:not(.example-expanded-row):hover {背景:#777;}

因此,如果行具有 address,我们只需要将 example-element-row 类添加到我们的行中.如果它没有地址,则该行不应该是可点击的,也不应该有一个悬停来向用户表明该行实际上是不可点击的.

<tr mat-row *matRowDef="let element; columns: columnsToDisplay;"[class.example-element-row]="element.addresses?.data.length"[class.example-expanded-row]="expandedElement === 元素"(点击)=toggleRow(元素)"></tr>

toggleRow 中,我们将定义当您单击模板中的一行时发生的逻辑.当用户点击此函数中的行时,我们还将实现sort.

@ViewChildren('innerSort') innerSort: QueryList;切换行(元素:用户){element.addresses &&(element.addresses as MatTableDataSource
).data.length ?(this.expandedElement = this.expandedElement === element ? null : element) : null;this.cd.detectChanges();this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource
).sort = this.innerSort.toArray()[index]);}

最后,我们需要定义 applyFilter 函数,以便过滤嵌套表.

@ViewChildren('innerTables') innerTables: QueryList>;应用过滤器(过滤器值:字符串){this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource
).filter = filterValue.trim().toLowerCase());}

这是一个关于 StackBlitz 的工作示例.

I have the below data

[
    {
        "_id": "c9d5ab1a",
        "subdomain": "wing",
        "domain": "aircraft",
        "part_id": "c9d5ab1a",
        "info.mimetype": "application/json",
        "info.dependent": "parent",
        "nested": [
            {
                "domain": "aircraft",
                "_id": "c1859902",
                "info.mimetype": "image/jpeg",
                "info.dependent": "c9d5ab1a",
                "part_id": "c1859902",
                "subdomain": "tail"
            }
        ]
    },
    {
        "_id": "1b0b0a26",
        "subdomain": "fuel",
        "domain": "aircraft",
        "part_id": "1b0b0a26",
        "info.mimetype": "image/jpeg",
        "info.dependent": "no_parent"
    }
]

Here if "info.dependent": "parent" then it is nested and if "info.dependent": "no_parent" then it does not have a child. I tried to create a dynamic table but I am stuck on how to make it collapsible/expandable with a nested table. Here is my code on stackblitz.

<mat-table class=" mat-elevation-z8" [dataSource]="dataSource">

    <ng-container [matColumnDef]="col" *ngFor="let col of displayedColumns">
        <mat-header-cell *matHeaderCellDef> {{ col }} </mat-header-cell>
        <mat-cell *matCellDef="let element"> {{ element[col] }} </mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row;columns:displayedColumns"></mat-row>

</mat-table>

.ts

public data = [
    {
        "_id": "c9d5ab1a",
        "subdomain": "wing",
        "domain": "aircraft",
        "part_id": "c9d5ab1a",
        "info.mimetype": "application/json",
        "info.dependent": "parent",
        "nested": [
            {
                "domain": "aircraft",
                "_id": "c1859902",
                "info.mimetype": "image/jpeg",
                "info.dependent": "c9d5ab1a",
                "part_id": "c1859902",
                "subdomain": "tail"
            }
        ]
    },
    {
        "_id": "1b0b0a26",
        "subdomain": "fuel",
        "domain": "aircraft",
        "part_id": "1b0b0a26",
        "info.mimetype": "image/jpeg",
        "info.dependent": "no_parent"
    }
];

dataSource = new MatTableDataSource([]);
displayedColumns = ['_id', 'subdomain', 'domain', 'part_id', 'info.mimetype', 'info.dependent'];

constructor(){
    this.displayedColumns = this.displayedColumns;
    this.dataSource = new MatTableDataSource(this.data);
}

Required format :-->

The nested format is like below

row 1 --> _id ,subdomain,domain,info.dependent

When we click on that particular row, then it has to expand and display the nested data in a table with the column names and row data.

"nested": [
    {
        "domain": "aircraft",
        "_id": "c1859902",
        "info.mimetype": "image/jpeg",
        "info.dependent": "c9d5ab1a",
        "part_id": "c1859902",
        "subdomain": "tail"
    }
]

解决方案

Note: For those who want to skip the lengthy explanation, here is the StackBlitz example.

What you actually want is to create a nested mat-table where all the nested tables are sortable and can be filtered through as well.

Firstly, since you need to use filtering and sorting in your nested table, you need to create a new MatTableDataSource for it. This can be done initially when you create the main dataSource in the ngOnInit like below.

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);

From the expandable rows example in the docs, we can see how to create an expandable row. In the expandable row, we will now have a table along with the Filter input. We will add some conditions so that the row is expandable only if there are addresses present.

<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>

Now that the row expands only if there are nested elements, we need to get rid of the hover for the users which have no addresses

Here is the CSS responsible for adding a background-color on hover

tr.example-element-row:not(.example-expanded-row):hover {
    background: #777;
}

So we just need to add the example-element-row class to our row if the row has an address. If it has no address, the row should not be clickable and there should not be a hover which indicates to the user that the row is in fact not clickable.

<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>

In toggleRow, we will define the logic for what happens when you click a row in the template. We will also implement sort when the user clicks on the row in this function.

@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]);
}

Finally, we need to define the applyFilter function so the nested tables can be filtered.

@ViewChildren('innerTables') innerTables: QueryList<MatTable<Address>>;

applyFilter(filterValue: string) {
    this.innerTables.forEach((table, index) => (table.dataSource as MatTableDataSource<Address>).filter = filterValue.trim().toLowerCase());
}

Here is a working example on StackBlitz.

这篇关于如何使用角材料在具有可扩展行的表格中创建嵌套垫表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆