Как применить несколько фильтров в таблице данных угловых материалов?

Привет, у меня есть таблица данных с 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
    }
  }

Вышеупомянутая функция выполняет фильтрацию, но когда я очищаю значение фильтра, данные таблицы не меняются. Также он не меняется, когда я удаляю персонажа.


person Saif Ali    schedule 19.04.2019    source источник
comment
Предоставьте stackblitz, если это возможно   -  person Prashant Pimpale    schedule 19.04.2019
comment
Это у меня работает!   -  person Prashant Pimpale    schedule 19.04.2019
comment
Вопрос не ясен! Что вы имеете в виду под Name which has marks > 90 and from 'abc' School от того места, где вы проходите 90 оценки и abc название школы   -  person Prashant Pimpale    schedule 19.04.2019
comment
@PrashantPimpale это означает - предположим, я хочу отфильтровать имя ученика с отметками › 90 и из школы «abc».   -  person Saif Ali    schedule 19.04.2019
comment
как? Можете ли вы показать все связанные HTML-код и TS?   -  person Prashant Pimpale    schedule 19.04.2019
comment
Попробуйте сослаться на этот ответ: https://stackoverflow.com/questions/51515695/filtering-Different-columns-in-a-material-table   -  person Tushar    schedule 06.05.2019


Ответы (4)


Для удобства объявим интерфейс TableFilter:

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

Функция предиката фильтра вызывается один раз для каждой строки (!) при применении фильтрации: если предикат возвращает значение 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;
  }

После этого вы можете применить свой фильтр следующим образом:

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

Это немного хакерски, что нам нужно установить фильтры как «любые»; но функция фильтра ожидает строку, и я не нашел другого способа обойти это.

person grreeenn    schedule 10.07.2019

Вы можете сделать это, заменив функцию 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);
}
person luke    schedule 18.09.2020

Хотя ответ от greeenn совершенно прекрасен, я не смог совместить несколько значений фильтра с этим подходом. Вот что я придумал:

Массив фильтров будет состоять из нескольких объектов

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.

person JB17    schedule 09.10.2020

Я смог разобраться!

  1. Получите исходные данные из DataSource в 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")
    }
  }

person Saif Ali    schedule 19.04.2019