Угловой материал - таблица фильтров по нескольким фильтрам и нескольким значениям фильтров одновременно - PullRequest
0 голосов
/ 26 января 2019

Я пытаюсь использовать два разных фильтра для таблицы объектов. Первый - это обычный фильтр на основе текста и ввода и работает как положено.

Второй, который я пытаюсь заставить работать, - это ряд флажков с надписью «Уровень 1», «Уровень 2» и т. Д. При установке флажка я хочу отфильтровать по столбцу «уровень» все проверенные в настоящий момент флажки. В идеале пользователь может фильтровать таблицу как по тексту, так и по уровню выбора

Я читал об использовании filterPredicate и пытался использовать в качестве шаблона , но я, должно быть, что-то упустил, любые указатели приветствуются.

Текущий фрагмент кода:

HTML:

//Input for text filter
<mat-form-field >
  <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter...">
</mat-form-field>

...

//Checkboxes for level filter
<div fxLayout="row" fxLayoutAlign="space-between center" class="margin-1">
    <mat-checkbox (change)="customFilterPredicate()" [(ngModel)]="level.active" *ngFor="let level of levelsToShow">{{level.level}}</mat-checkbox>
</div>

TS

ngOnInit() {
     this.dataSource.filterPredicate = this.customFilterPredicate();
  }

...

applyFilter(filterValue: string) {
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }

customFilterPredicate() {
    const myFilterPredicate = (data): boolean => {
      return this.levelsToShow.some(data['level'].toString().trim());
    };
    return myFilterPredicate;
  }

Обновление

До сих пор мне удалось добиться некоторого прогресса благодаря Фабиану Кунгу, но я все еще не свободен дома. Чтобы уточнить, я надеюсь, что текстовый фильтр сможет выполнять поиск по нескольким столбцам («castingTime», «duration» и т. Д.), А флажки будут фильтроваться только по уровню (странные запросы, но я делаю это для друга так что я просто пытаюсь помочь ему).

На данный момент, когда я нажимаю на флажок, я получаю эту ошибку: 'Не удается прочитать свойство' toLowerCase 'из неопределенного' которая указывает на эту строку кода:

return data['level'].toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1 &&

но когда я утешаю данные для выхода из системы, я вижу, что они имеют свойство level, поэтому я не вижу, в чем я ошибаюсь.

Любая помощь приветствуется, спасибо!

Вот соответствующие фрагменты кода:

    HTML:

        <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter..." [formControl]="textFilter">

        <mat-checkbox (change)="updateFilter()" [(ngModel)]="level.active" *ngFor="let level of levelsToShow">{{level.name}}</mat-checkbox>

    TS:

        levelsToShow: Level[] = [
            { level: '1', active: false, name: 'Level 1' },
            { level: '2', active: false, name: 'Level 2' },
            { level: '3', active: false, name: 'Level 3' },
            { level: '4', active: false, name: 'Level 4' },
            { level: '5', active: false, name: 'Level 5' },
            { level: '6', active: false, name: 'Level 6' },
            { level: '7', active: false, name: 'Level 7' },
            { level: '8', active: false, name: 'Level 8' },
            { level: '9', active: false, name: 'Level 9' }
          ];

          levelFilter = new FormControl();
          textFilter = new FormControl();
          globalFilter = '';

          filteredValues = {
            level: '', 
            text: '', 
          };

ngOnInit() {
    ...

    this.textFilter.valueChanges.subscribe((textFilterValue) => {
      this.filteredValues['text'] = textFilterValue;
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });

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

  customFilterPredicate() {
    const myFilterPredicate = (data: Spell, filter: string): boolean => {
      var globalMatch = !this.globalFilter;

      if (this.globalFilter) {
        // search all text fields
        globalMatch = data['spellName'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['level'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['castingTime'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['distance'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['details'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['duration'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['school'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['effect'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1;
      }

      if (!globalMatch) {
        return;
      }

      let searchString = JSON.parse(filter);

      return data['level'].toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1 &&
        (this.levelsToShow.filter(level => !level.active).length === this.levelsToShow.length ||
          this.levelsToShow.filter(level => level.active).some(level => level.level === data.level.toString()));
    }
    return myFilterPredicate;
  }

  updateFilter() {
    this.dataSource.filter = JSON.stringify(this.filteredValues);
  }

Обновление II

В соответствии с запросом приведен пример одной из строк таблицы: (на случай, если это поможет, для таблицы заклинаний Д и Д для друга)

{
castingTime: "1 half action"
distance: "Short range attack"
duration: "1 round per Casting Level"
effect: "Once per round, you may take a half action to launch an arrow of acid from your palm, generating a new Spellcasting result to see if you hit.Each arrow inflicts 1d6 acid damage.↵  "
index: 0
level: "4"
school: "Creation"
spellName: "ACID ARROW"
}

* Окончательное обновление * Это то, с чем я столкнулся на случай, если кто-нибудь застрянет. Спасибо Фабиану Кунгу за все это! Единственное странное замечание - это то, что я использовал фактическое значение текстового ввода "textFilter", потому что строковое преобразование текста FilterValues ​​и последующий их синтаксический анализ (фильтр принимает только строки, насколько я могу судить) продолжали давать мне сообщение "Ошибка JSON , неожиданное значение в 0 "сообщениях, и насколько я могу судить, это будет работать нормально, КРОМЕ теперь мне нужно выяснить, как регулировать фильтр.

Но это уже другой вопрос! Лол.

Спасибо!

customFilterPredicate() {
    const myFilterPredicate = (data: Spell, filter: string): boolean => {
      var globalMatch = !this.globalFilter;

      if (this.globalFilter) {
        // search all text fields
        globalMatch = data['spellName'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['level'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['castingTime'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['distance'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['details'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['duration'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['school'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1 ||
                      data['effect'].toString().trim().toLowerCase().indexOf(this.globalFilter.toLowerCase()) !== -1;
      }

      if (!globalMatch) {
        return;
      }

      return data.spellName.toString().trim().toLowerCase().indexOf(this.textFilter.value) !== -1 &&
        (this.levelsToShow.filter(level => !level.active).length === this.levelsToShow.length ||
          this.levelsToShow.filter(level => level.active).some(level => level.level === data.level.toString()));
    }
    return myFilterPredicate;
  }

1 Ответ

0 голосов
/ 27 января 2019

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

Я взял связанный стек и изменил его, чтобы сделатьон работает с вашими флажками, отметьте его здесь .

В шаблоне у вас есть свои флажки, как вы его установили:

<mat-checkbox (change)="updateFilter()" [(ngModel)]="level.active" *ngFor="let level of levelsToShow">{{level.name}}</mat-checkbox>

В компонентеЯ добавил Level интерфейс:

export interface Level {
  active: boolean;
  name: string;
  level: number;
}

и некоторые данные:

levelsToShow: Level[] = [
  { level: 1, active: false, name: 'Level 1' },
  { level: 2, active: false, name: 'Level 2' },
  { level: 3, active: false, name: 'Level 3' },
];

И самая важная часть в функции customFilterPredicate.Он фильтрует свойство name в первом условии, а во втором проверяет, установлены ли все уровни на false, в этом случае мы возвращаем true, так как я предполагаю, что вы хотите увидеть все уровниесли флажок не установленЕсли уровень активен, мы фильтруем по этому уровню или по нескольким уровням, если выбрано несколько.

return data.name.toString().trim().toLowerCase().indexOf(searchString.name.toLowerCase()) !== -1 &&
        (this.levelsToShow.filter(level => !level.active).length === this.levelsToShow.length ||
         this.levelsToShow.filter(level => level.active).some(level => level.level === data.level));

Небольшая, но важная часть заключается в том, чтобы фактически активировать фильтрацию при установке / снятии флажка.Это можно сделать, просто заново установив источник данных filter и вызывая его при каждом изменении значения флажка:

updateFilter() {
  this.dataSource.filter = JSON.stringify(this.filteredValues);
}
...