如何在 Angular Material Data Table 中应用多个过滤器?

Sai*_*Ali 6 angular-material angular

嗨,有一个包含 4 列的数据表 - 姓名、年龄、分数、学校。现在我想为每一列应用过滤器。过滤器单独工作正常。但我无法合并过滤器的结果 - 例如,我无法过滤掉标记 > 90 和来自“abc”学校的名称。

我试过这样的事情,但没有奏效。

applyFilter(filterValue: string) {
    console.log("Filter is applied upon:",this.dataSource)
    let initialDataSource = this.dataSource;
    this.dataSource.filter = filterValue.trim().toLowerCase();
    this.filteredDataSource = this.dataSource.filteredData
    this.filterVal = this.dataSource.filter;
    if(this.filterVal.length != 0){
      this.dataSource = new MatTableDataSource(this.filteredDataSource);
      this.dataSource.filter = filterValue.trim().toLowerCase();
    }else{
      this.dataSource = initialDataSource;
      this.dataSource.filter = filterValue.trim().toLowerCase();
      this.filteredDataSource = this.dataSource.filteredData
    }
  }
Run Code Online (Sandbox Code Playgroud)

上面的函数做了过滤,但是当我清除过滤值时,表数据不会改变。当我删除一个字符时它也不会改变。

grr*_*enn 5

为了方便起见,声明 TableFilter 接口:

interface ITableFilter {
  column: string;
  value: any;
}
Run Code Online (Sandbox Code Playgroud)

应用过滤时,过滤谓词函数每行调用一次(!):如果谓词返回 true,则当前行将包含在过滤结果中。因此,我们将迭代过滤器数组,如果其中一列不匹配,则返回 false。

将您的 dataSource filterPredicate 替换为以下自定义的:

  setDataSource() {
    this.dataSource = new MatTableDataSource(this.yourData);
    this.dataSource.filterPredicate = this.customFilterPredicate;
  }

   
  customFilterPredicate(data: any, filters: ITableFilter[]): boolean {        
    for (let i = 0; i < filters.length; i++) {
      const fitsThisFilter = data[filters[i].column].includes(filters[i].value);
      if (!fitsThisFilter) {
        return false;
      }
    }
    return true;
  }
Run Code Online (Sandbox Code Playgroud)

之后你可以像这样应用你的过滤器:

// implement some relevant logic to build the filters array
const filter: ITableFilter | any = [{column: 'name', value: 'foo'}, {column: 'description', value: 'bar'}];
// this is how you apply a filter
this.dataSource.filter = filter;
Run Code Online (Sandbox Code Playgroud)

我们需要将过滤器设置为“任意”,这有点黑客行为;但过滤器函数需要一个字符串,我没有找到其他方法来绕过它。


JB1*_*B17 5

尽管grreeenn的答案非常好,但我无法用这种方法组合多个过滤器值。这就是我想出的:

过滤器数组将由多个对象组成

const filters = [{key: name, filterValue: 'Mark'}, {key: score, filterValue: 1}]
Run Code Online (Sandbox Code Playgroud)

要使 filterPredicate 接受列表,您可以使用以下命令对数组进行字符串化

JSON.stringify(filters)
Run Code Online (Sandbox Code Playgroud)

我稍微更改了 filterPredicate 方法,以便同时处理多个值

customFilterPredicate(data: any, filters: string): boolean {
  let match = true;
  const filtersList = JSON.parse(filters)
  filtersList.forEach(filterObj => {
    match = match && data[filterObj.key].toLocaleLowerCase().indexOf(filterObj.filterValue.toLocaleLowerCase()) !== -1;
  });
  return match;
};
Run Code Online (Sandbox Code Playgroud)

因此,如果所有值都匹配,过滤器只会返回 true,否则返回 false。


Sai*_*Ali -2

我能弄清楚!

  1. 在 ngOnInit 中从 DataSource 获取初始数据。

ngOnInit() {
    
    this.httpService.get('./assets/emp.json').subscribe(
      data => {
        this.headers = data;
        this.dataSource = new MatTableDataSource(this.headers);
        this.initialData = this.dataSource.data;
        this.dataSource.paginator = this.paginator;
        // console.log(data);
      },
      (err: HttpErrorResponse) => {
        console.log(err.message);
      }
    );
  }
Run Code Online (Sandbox Code Playgroud)

  1. 将 applyFilter() 方法编写为 -

 applyFilter(filterValue: string) {
    let filteredData;
    // let initialData = this.dataSource.data;
    console.log("iniital data", this.initialData)
    if (filterValue.length != 0) {
      console.log("data source:", this.dataSource)
      this.dataSource.filter = filterValue.trim().toLowerCase();
      filteredData = this.dataSource.filteredData;
      this.dataSource.data = filteredData
      console.log("Filtered Data", filteredData);
    } else {
      this.dataSource.data = this.initialData
      console.log("Its empty")
    }
  }
Run Code Online (Sandbox Code Playgroud)