【问题标题】:Angular Material 2 DataSource filter with nested object带有嵌套对象的Angular Material 2 DataSource过滤器
【发布时间】:2018-04-14 15:53:01
【问题描述】:

我有材质 2 的 angular 4 项目,我想过滤 MatTable 中的数据。当我们过滤非嵌套字段上的数据时,DataSource 过滤器工作正常。

this.dataSource = new MatTableDataSource([
     { orderNumber: 1, orderInfo: { type: 'ABC'}, date: '12/3/2012 9:42:39 AM'},
     { orderNumber: 3, orderInfo: { type: 'Hello' }, date: '12/2/2018 9:42:39 AM'},
]);

过滤器对 orderNumber、日期工作正常,但不能与 orderInfo 对象中的类型字段正常工作。

【问题讨论】:

  • 请贴出过滤逻辑。
  • applyFilter(filterValue: string) { filterValue = filterValue.trim(); filterValue = filterValue.toLowerCase(); this.dataSource.filter = filterValue; }

标签: angular angular-material2


【解决方案1】:

这是一个包含递归的解决方案,因此您不必对每个嵌套对象或其键/值对进行硬编码。

this.dataSource.filterPredicate = (data, filter: string)  => {
  const accumulator = (currentTerm, key) => {
    return this.nestedFilterCheck(currentTerm, data, key);
  };
  const dataStr = Object.keys(data).reduce(accumulator, '').toLowerCase();
  // Transform the filter by converting it to lowercase and removing whitespace.
  const transformedFilter = filter.trim().toLowerCase();
  return dataStr.indexOf(transformedFilter) !== -1;
};

还有nestedFilterCheck

nestedFilterCheck(search, data, key) {
  if (typeof data[key] === 'object') {
    for (const k in data[key]) {
      if (data[key][k] !== null) {
        search = this.nestedFilterCheck(search, data[key], k);
      }
    }
  } else {
    search += data[key];
  }
  return search;
}

感谢@Sagar Kharche 覆盖filterPredicate

【讨论】:

  • 当我添加这个 filterPredicate 时,我的标记应该是什么样子?我目前过滤事件(根据材料文档),如下所示:
  • @RinandLen 你会想要<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">,然后在你的代码中像这样applyFilter(filterValue: string) { filterValue = filterValue.trim(); // Remove whitespace filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches this.dataSource.filter = filterValue; }
【解决方案2】:

DataSource 有filterPredicate() 方法,需要在我们的应用程序中重写,如下所示。数据源初始化后,将此代码添加到您的组件中。

this.dataSource.filterPredicate = (data, filter: string)  => {
  const accumulator = (currentTerm, key) => {
    return key === 'orderInfo' ? currentTerm + data.orderInfo.type : currentTerm + data[key];
  };
  const dataStr = Object.keys(data).reduce(accumulator, '').toLowerCase();
  // Transform the filter by converting it to lowercase and removing whitespace.
  const transformedFilter = filter.trim().toLowerCase();
  return dataStr.indexOf(transformedFilter) !== -1;
};

【讨论】:

  • 之前添加:- this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort;或 this.dataSource 初始化后 ngOnInit() 方法中的任何位置。
  • Angular 6 还没有更聪明的方法吗?排序也不起作用,如果我们有多个列,添加这个谓词 x 次非常难看......
  • @badera 查看我发布的答案以解决您的问题
  • @badera 不幸的是,它今天仍然无法正常工作。非常荒谬的是它仍然不遍历内部嵌套对象。
  • @badera 过滤只使用接受的答案。但是,对于排序,您可以使用材料表的 sortDataAccessor,即只需在您的 filterPredicate 之后使用此代码。 this.dataSource.sortingDataAccessor = (item, property) => { switch(property) { case 'columnHeaderName': return item.orderInfo.type; //定义剩余列标题的其他情况 default: return ""; } };
【解决方案3】:

这是一个非常通用的解决方案,肯定会奏效。它不依赖于json的结构,无论是简单的还是嵌套的,这个解决方案都适用。

this.dataSource.filterPredicate = (data: any, filter) => { const dataStr =JSON.stringify(data).toLowerCase(); return dataStr.indexOf(filter) != -1; }

【讨论】:

  • 非常聪明的解决方案,但是这也会搜索 属性名称
  • 简单优雅!很好回答!
  • 这很好用!但是你怎么能消除@JeffreyRoosendaal 提出的问题呢? (关于此搜索属性名称)。
  • 如果你有多个数字或布尔值,这不起作用,只有字符串。否则有一个true 或另一个字段中的确切数值将使项目被过滤,即使确切的属性没有所需的值。
  • 但是这也会搜索属性名称。 – Jeffrey Roosendaal 为此尝试仅将 dataStr 附加到您希望使其可搜索的值。例如。 - {"name":"Chandan"} const dataStr = JSON.stringify(data.name) 我们可以为数据数组创建循环,这很明显。
猜你喜欢
  • 1970-01-01
  • 2018-03-23
  • 2018-07-31
  • 1970-01-01
  • 2016-03-23
  • 1970-01-01
  • 2020-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多