Фильтровать MatTableDataSource, используя содержимое массива

У меня есть таблица в моем приложении Angular, которая отображает пользовательские данные в своих строках. Я хочу иметь возможность фильтровать эту таблицу, используя массив строк, представляющих электронные письма пользователей. Если адрес электронной почты пользователя существует в массиве, я не хочу, чтобы пользователь отображался в таблице.

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

Однако я не могу найти никаких решений для использования массива строк для фильтрации данных. Нужно ли мне объединить весь массив в строку, а затем передать ее в свойство filterPredicate?

    applyAddedUserFilter() {
        this._usersService.addedUsers$.subscribe((addedUsers: AddedUser[]) => {
          let addedUserEmails: string[] = addedUsers.map(({ email }) => email);

          this.users.filterPredicate = (user: GoogleUser, filter: string) => { //<-- What exactly do I need to do here to use my string[] to filter my table's results?
            //Unsure what I need to do here.
          }
        });
      }

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


person Jake12342134    schedule 06.08.2019    source источник
comment
возможно, попробуйте что-то вроде этого: let filteredData = this.users.filter(user => !(addedUserEmails.indexOf(user.email) > -1)); Затем вы можете добавить это --› this.dataSource.data = filteredData;   -  person sagat    schedule 06.08.2019
comment
да. Я бы предложил сделать это вместо filterpredicate и напрямую отфильтровать массив и установить его в datasource.data. Это должно работать.   -  person sagat    schedule 06.08.2019
comment
@sagat Можете ли вы отредактировать исходный пост, чтобы показать мне, как вы это реализуете? Если я попытаюсь выполнить this.users.filter(user => !(addedUserEmails.indexOf(user.email) > -1));, я получу ошибку компилятора.   -  person Jake12342134    schedule 06.08.2019
comment
сначала дайте мне понять --› addUserEmails - это массив с условиями фильтра, то есть, если письмо есть, вы не хотите показывать пользователя в таблице. Как называется массив пользователей, который вы хотите отфильтровать. Можете ли вы опубликовать весь component.ts   -  person sagat    schedule 06.08.2019
comment
this.users это users: MatTableDataSource<GoogleUser> = new MatTableDataSource([]);, все, что я хочу сделать, это отфильтровать данные, чтобы, если какие-либо электронные письма в источнике данных существовали в addedUserEmails, они не отображались в таблице   -  person Jake12342134    schedule 06.08.2019
comment
Хорошо, я сделал stackblitz. Ответ через секунду   -  person sagat    schedule 06.08.2019
comment
Приятель, возможно, вам нужно сделать это MatTableDataSource‹GoogleUser[]›, вы не указали набор пользователей, а одного пользователя.   -  person sagat    schedule 06.08.2019


Ответы (2)


Я бы сделал это так:

applyAddedUserFilter() {
    this._usersService.addedUsers$.subscribe((addedUsers: AddedUser[]) => {
      let addedUserEmails: string[] = addedUsers.map(user => user.email);

      this.dataSource.data = this.users.filter((user: GoogleUser) => !(addedUserEmails.indexOf(user.email) > -1));
    });
  }

Вот stackblitz: Фильтр таблицы материалов

person sagat    schedule 06.08.2019
comment
Cannot invoke an expression whose type lacks a call signature. Type 'String' has no compatible call signatures. Это ошибка компилятора, которую я получаю при попытке использовать эту строку кода. - person Jake12342134; 06.08.2019
comment
Вы проверяли стекблиц? Можете ли вы предоставить свой код компонента while? - person sagat; 06.08.2019
comment
Это связано с тем, что ваш GoogleUser Type и String не являются одними и теми же типами. - person sagat; 06.08.2019

Это поздний ответ, но, безусловно, поможет тем, кто заинтересован.

Вы можете использовать mat-table-filter для фильтрации. Он также поддерживает фильтрацию массивов. Это избавляет вас от внедрения шаблонов фильтрации, включая устранение дребезга и т. д.

Единственное, что вам нужно сделать, это добавить директиву matTableFilter в вашу таблицу материалов и связать exampleEntity с представлением того, что у вас есть как элемент внутри вашего источника данных.

 <table mat-table matTableFilter [dataSource]="dataSource"
 [exampleEntity]="exampleObject"...>

Это все. Когда вы заполняете свойства exampleObject, фильтр автоматически будет работать нормально с поддержкой устранения дребезга по умолчанию. Вы также можете изменить время отката.

Вы можете посмотреть примеры здесь: https://halittalha.github.io/ng-material-extensions/

Ниже я привожу полный исходный код фильтрации массива. В приведенном ниже примере используется компонент chips для сбора содержимого массива для фильтрации.

.html

<mat-table matTableFilter [exampleEntity]="filterEntity" [filterType]="filterType" [dataSource]="dataSource"
  class="mat-elevation-z8">
  <ng-container matColumnDef="category">
    <mat-header-cell *matHeaderCellDef>
      <mat-form-field appearance="outline">
        <input matInput placeholder="Category" [(ngModel)]="filterEntity.category">
      </mat-form-field>
    </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.category}} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="brand">
    <mat-header-cell *matHeaderCellDef>
      <mat-form-field appearance="outline">
        <input matInput placeholder="Product Brand" [(ngModel)]="filterEntity.brand">
      </mat-form-field>
    </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.brand}} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="availableSizes">
    <mat-header-cell *matHeaderCellDef>

      <mat-form-field class="example-chip-list">
        <mat-chip-list #chipList aria-label="Fruit selection">
          <mat-chip *ngFor="let size of filterEntity.availableSizes" [selectable]="true" [removable]="true"
            (removed)="remove(size)">
            {{size}}
            <mat-icon matChipRemove>cancel</mat-icon>
          </mat-chip>
          <input placeholder="Add Size" [matChipInputFor]="chipList"
            [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="true"
            (matChipInputTokenEnd)="add($event)">
        </mat-chip-list>
      </mat-form-field>
    </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.availableSizes}} </mat-cell>
  </ng-container>

  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>

.ts

import { MatTableFilter } from 'mat-table-filter';
import { Component, OnInit } from '@angular/core';
import { MatTableDataSource, MatChipInputEvent } from '@angular/material';
import { COMMA, ENTER } from '@angular/cdk/keycodes';

export class Product {
  category: string;
  brand: string;
  availableSizes: Array<string>;
}

const PRODUCTS: Product[] = [
  {category: 'T-Shirt', brand: 'X', availableSizes: ['S', 'M', 'L', 'XL']},
  {category: 'T-Shirt', brand: 'Y', availableSizes: ['S', 'L', 'XL']},
  {category: 'T-Shirt', brand: 'Z', availableSizes: ['XL']},
  {category: 'Jean', brand: 'X', availableSizes: ['S', 'M', 'L', 'XL']},
  {category: 'Jean', brand: 'Y', availableSizes: ['S', 'M']},
  {category: 'Jean', brand: 'Z', availableSizes: ['S', 'M', 'L']},
  {category: 'Jean', brand: 'B', availableSizes: ['S', 'M', 'L']},
  {category: 'Jacket', brand: 'X', availableSizes: ['S', 'L', 'XL']},
  {category: 'Jacket', brand: 'Z', availableSizes: ['S']},
  {category: 'Pants', brand: 'X', availableSizes: ['S', 'M', 'L', 'XL']},
  {category: 'Pants', brand: 'Y', availableSizes: ['L', 'XL']},
  {category: 'Pants', brand: 'Z', availableSizes: ['S']},
  {category: 'Hat', brand: 'X', availableSizes: ['S', 'M', 'L']},
  {category: 'Skirt', brand: 'X', availableSizes: ['S', 'M', 'L', 'XL']},
  {category: 'Skirt', brand: 'Y', availableSizes: ['S', 'M', 'L']}
 ];

@Component({
  selector: 'app-array-filter',
  templateUrl: './array-filter.component.html',
  styleUrls: ['./array-filter.component.css']
})
export class ArrayFilterComponent implements OnInit {
  filterEntity: Product;
  filterType: MatTableFilter;
  displayedColumns: string[] = ['category', 'brand', 'availableSizes'];
  dataSource;
  readonly separatorKeysCodes: number[] = [ENTER, COMMA];

  add(event: MatChipInputEvent): void {
    const input = event.input;
    const value = event.value;

    if ((value || '').trim()) {
      this.filterEntity.availableSizes.push(value.trim());
    }

    // Reset the input value
    if (input) {
      input.value = '';
    }
  }

  remove(size: string): void {
    const index = this.filterEntity.availableSizes.indexOf(size);

    if (index >= 0) {
      this.filterEntity.availableSizes.splice(index, 1);
    }
  }

  ngOnInit() {
    this.filterEntity = new Product();
    this.filterEntity.availableSizes = new Array<string>(); // DO NOT FORGET TO INIT THE ARRAY
    this.filterType = MatTableFilter.ANYWHERE;
    this.dataSource = new MatTableDataSource(PRODUCTS);
  }
}
person talhature    schedule 04.06.2020