В таблице материалов Angular 5 заменить filterPredicate функцией с разными типами параметров.

В настоящее время я работаю над компонентом, который использует таблицу материалов 2 для отображения некоторых данных. Мне нужно иметь возможность писать собственные операции фильтрации (например, цена> 1) и комбинировать несколько фильтров. Чтобы это сработало, я написал собственный filterPredicate:

customFilterPredicate(data: Coin, filters: Predicate[]): boolean {
  var operators = {
    '>=': function(a, b){
      return +a >= +b
    },
    '<=': function(a, b){
      return +a <= +b
    }
  }

  if(filters.length == 0) return true;
  let res = false;

  for(var i = 0; i < filters.length; i++){
    let conditionMet = operators[filters[i].op](data[filters[i].columnName], filters[i].val);
    if(conditionMet) {
      res = true;
    } else {
      res = false;
      break;
    }
  }
  return res
} 

интерфейс для типа предиката:

export interface Predicate {
  field: columnName
  op: string;
  val: number;
  visible: boolean;
}

CustomFilterPredicate проходит через все фильтры, переданные как параметр, и возвращает true, если все условия выполнены, и false, если одно или несколько условий не выполняются.

Теперь я использую эту функцию, чтобы получить данные для таблицы через службу, установить свой источник данных и заменить filterPredicate источника данных:

  setData(){
    return new Promise((resolve, reject) => {
      return this.coinService.getCoins()
      .subscribe(coins => {
          resolve(coins)
        })
    })
    .then((data: Coin[]) => {
      this.dataSource = new MatTableDataSource<Coin>(data);
      this.dataSource.filterPredicate = this.customPredicate;
    })
  }

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

Итак, у меня вопрос: как я могу заменить this.dataSource.filterPredicate моим, не переписывая функцию в пакете материала 2. Есть ли способ сделать это в машинописном тексте?

И если у кого-то есть идея, почему это работает, несмотря на то, что выдает ошибку, это было бы интересно, ха-ха


person Paul Etscheit    schedule 17.04.2018    source источник
comment
Возможно, он был недавно обновлен, но разве вы уже не можете сделать это, установив функцию filterPredicate? filterPredicate = (data: any, filter: string) = ›{(Ваш фильтр здесь)} Затем вы берете строку фильтра и конвертируете ее в объект JavaScript? Вроде хаки..но работает   -  person Braden Brown    schedule 30.06.2018


Ответы (2)


В настоящее время это не поддерживается, но есть открытый запрос функции на Github. Он был добавлен в список функций, поэтому, возможно, за ним стоит следить.

В этом выпуске предлагается создать свой собственный DataSource с фильтром, принимающим массивы вместо строк. Взгляните на MatTable a>, который расширяет DataSource класс.

person Kim Kern    schedule 17.04.2018
comment
Понятно, сейчас я изменил тип на любой, и ошибка больше не выдается, но я еще раз посмотрю позже, чтобы найти лучшее решение. Спасибо! - person Paul Etscheit; 18.04.2018

В качестве обходного пути вы можете использовать bind () при установке filterPredicate:

    this.dataSource.filterPredicate = this.customFilterPredicate.bind(this);

Затем вы получаете доступ к локальным переменным, в моем случае:

customFilterPredicate(data: Area, filter: string): boolean {
    return this.filterMatchesString(JSON.stringify(data), this.searchFilter) &&
        this.filterMatchesString(data.Area, this.areaFilter) &&
        this.filterMatchesString(data.Abbreviation, this.abbreviationFilter);
}

В вашем случае это будет массив предикатов. Однако всякий раз, когда изменяется какой-либо из предикатов, вам нужно обновить значение для фильтра, только тогда, когда эти изменения применяются повторно.

filterChange() {
    this.dataSource.filter = this._searchFilter + this._areaFilter + this._abbreviationFilter;
}
person Stephen Turner    schedule 17.09.2018