如何在角度材料数据表中应用多个过滤器?

时间:2019-04-19 05:55:52

标签: angular angular-material

您好,数据表有4个列,分别是姓名,年龄,标记,学校。现在,我想为每个列应用过滤器。过滤器可以单独正常工作。但是我无法组合过滤器的结果-例如,我无法从'abc'学校过滤出标记> 90的名称。

我尝试了类似的方法,但是没有用。

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

上面的函数进行过滤,但是当我清除过滤器值时,表数据不会更改。删除字符时也不会改变。

4 个答案:

答案 0 :(得分:1)

您可以通过用自己的过滤器函数替换filterPredicate函数并将多个值(作为对象)传递给过滤器来实现。

示例代码:

this.timeSlotDataSource.filterPredicate = (data: any, filterObjString: string) => {
    const filterObj = JSON.parse(filterObjString);
    const filterValue1 = filterObj.filterValue1;
    const filterValue2 = filterObj.filterValue2;
    const filterValue3 = filterObj.filterValue3;
    let available = false;

    // You may add additional logic here if needed
    if('your own logic')
         available = true;
    else
         return false;

    return available && 
         ( data.slotName.toLowerCase().indexOf(filterValue1) !== -1 || 
           data.slotInfo.toLowerCase().indexOf(filterValue2) !== -1 ||
           data.slotTime.toLowerCase().indexOf(filterValue3) !== -1);
}

filter(){
    const filterObj = { 
        filterValue1: this.filterValue1,
        filterValue2: this.filterValue2,
        filterValue3: this.filterValue3,
    };
    this.timeSlotDataSource.filter = JSON.stringify(filterObj);
}

答案 1 :(得分:0)

我能够弄清楚!

  1. 从ngOnInit中的数据源获取初始数据。

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

  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")
    }
  }

答案 2 :(得分:0)

这是一个更优雅的解决方案。

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

interface ITableFilter {
  column: string;
  value: any;
}

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

使用以下自定义变量替换您的dataSource filterPredicate:

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


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

之后,您可以像这样应用过滤器:

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

我们需要将过滤器设置为“ any”有点荒谬;但是filter函数需要一个字符串,没有其他方法可以解决它。

答案 3 :(得分:0)

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

filters数组将由多个对象组成

const filters = [{key: name, filterValue: 'Mark'}, {key: score, filterValue: 1}]

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

JSON.stringify(filters)

我稍微修改了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;
};

因此,过滤器仅在所有值都匹配时才返回true,否则将返回false。