如何一次过滤 mat 表数据源和相关的异步属性?

Posted

技术标签:

【中文标题】如何一次过滤 mat 表数据源和相关的异步属性?【英文标题】:How to FILTER mat table datasource AND related async properties at once? 【发布时间】:2020-12-12 16:29:53 【问题描述】:

设置: angular 9.1.7、angular-material 9.2.3、macOS 10.14.6、ngrx-store/ngrx-data/ngrx-entity 9.1.2

情况:

我有一个正常工作的材料表,其数据源类型为 MatTableDataSource,该数据源是从 ngrx Store 提供的异步 HTTP 请求中获得的。 我可以使用内置的数据源过滤功能过滤资源本身的所有属性。

问题:

在我的材料表组件中,我没有显示所有资源属性,某些列显示为特定资源属性异步加载的相关数据,例如:(element.orderId | orderContactProperty: 'email') | async - 资源(元素)具有orderId 属性,并且我还从同一服务器加载订单和联系人,当在某个时候,通过管道加载该资源的该订单的联系人并显示它的属性(“电子邮件”)。现在这显然不属于 Resource 类型的数据源,并且是稍后加载的,意味着它不能被过滤。

过滤这些不属于原始数据源的延迟加载属性的最佳/最简单的解决方案是什么?基本上,我如何过滤客户看到的表格中显示的内容?

什么可行?

我查看了mat-table-exporter 扩展,因为只导出了可见表数据,我的想法是提取包含所有可见数据的行,然后过滤,然后仅使用过滤后的元素更新数据源,但它似乎是一个 hack-ish 解决方法,对吧?

我还考虑过通过在显示相关属性之前解析相关属性并将它们添加到相应的行来“扩展”数据源,以便现在将它们包含在内以进行过滤 - 这也不会有问题,因为类型 Resource 不正确以后当我想编辑/更新资源并将它们保存到服务器时,我会有不需要的属性

但是,在将我的时间投入到这些想法中之前,是否有人建议/指导如何最好地解决这个问题?我肯定不是第一个偶然发现它的人,但找不到描述该确切场景的任何其他问题

不幸的是,由于它的复杂性并且它是一个客户项目,我无法提供 stackblitz,但是我希望这个屏幕截图有助于说明我的问题:(红色星号表示:不在数据源中并且无法过滤,其他的都很好)

【问题讨论】:

您是否需要过滤未在表格中显示的列? @talhature 不,不可见的列已经被过滤,因为它们在数据源中 - 我需要过滤不在数据源中但在其他可观察对象/服务的表中可见的列,并且以某种方式与数据源中的那些 【参考方案1】:

我遇到了完全相同的情况,并且很惊讶没有找到适合异步过滤数据的解决方案。 由于 filterPredicate 期望 boolean 作为返回类型,因此不可能以干净的方式将存储选择器中的 Observable 合并到数据源。

因此,我决定在本地缓存来自 store 的数据(在我的例子中是用户名),并扩展默认的 angular material filterPredicate。

这只有效,因为我已经在表格实际显示之前加载了数据,这限制了这种方法的用例。

filterPredicate: ((data: Data, filter: string) => boolean) = (data: Data, filter: string): boolean => 

    // default angular material filter predicate
    const dataStr = Object.keys(data).reduce((currentTerm: string, key: string) => 
    
      return currentTerm + (data as [key: string]: any)[key] + '◬';
    , '').toLowerCase();

    // Transform the filter by converting it to lowercase and removing whitespace.
    const transformedFilter = filter.trim().toLowerCase();

    const defaultResult = dataStr.indexOf(transformedFilter) !== -1;

    // no need to continue searching after a match
    if (defaultResult) 
      return true;
    

    // no match found yet, check usernames for matches
    const userIds = this.getUserIds(transformedFilter);
    return userIds.includes(data.userId);


然后可以将此函数分配给数据源的 filterPredicate,如https://material.angular.io/components/table/overview#filtering 中所述。

this.dataSource.filterPredicate = this.filterPredicate;

我知道这也不是一个干净的解决方案,但对于我的场景来说已经足够了。欢迎任何更好的方法!

【讨论】:

以上是关于如何一次过滤 mat 表数据源和相关的异步属性?的主要内容,如果未能解决你的问题,请参考以下文章

如何更新详细信息表中的数据并且不丢失范围选择和过滤器?

jquery Datatables过滤行

特定列上的角度表过滤器

当过滤器为空时,它返回空数组

Lumen/Laravel Eloquent - 按数据透视表中的属性过滤

如何自动增加表中的列?