【问题标题】:Angular material : mat-table multiple column filter on dynamic data角度材料:动态数据的垫表多列过滤器
【发布时间】:2020-11-19 08:28:27
【问题描述】:

我正在使用 Angular 材质表,显示我从后端获取的动态数据。单列搜索工作正常。现在我想实现多列搜索。谁能帮我实现这一目标?

HTML

<div >
  <ng-container *ngIf="columns && columns.length">
    <table mat-table matTableExporter [dataSource]="dataSource" #exporter="matTableExporter">
      <!-- actions -->
      <ng-container matColumnDef="actions">

        <th mat-header-cell *matHeaderCellDef>
          Update
          </th>

        <td class="trendCol icons" mat-cell *matCellDef="let element;">
          <button mat-icon-button  style="margin:5px;" color="accent" (click)="navigateToTrendEdit(element.unique_id)">
            <mat-icon aria-label="Edit">edit</mat-icon>
          </button>

          <button mat-icon-button style="margin:5px;" color="accent" (click)="deleteItem(element.unique_id)">
            <mat-icon aria-label="Delete">delete</mat-icon>
          </button>
        </td>
      </ng-container>
      <ng-container *ngFor="let column of columns; let i = index" [matColumnDef]="column.columnDef">
        <th mat-header-cell *matHeaderCellDef>
          {{ column.header }}
          <mat-icon class="filter_icon" (click)="openFilterDynamic(i)"
            >filter_alt</mat-icon
          ><br>
          <div *ngIf="openId === i">
            <mat-form-field>
              <input
                matInput
                type="text" [(ngModel)]="searchValue"
                class="form-field"
                (ngModelChange)="onSearchChange(column.columnDef)"
              />
              <button mat-button *ngIf="searchValue" matSuffix mat-icon-button aria-label="Clear" (click)="closeSearch(column.columnDef)">
                <mat-icon>close</mat-icon>
              </button>
            </mat-form-field>
          </div>
        </th>
        <td class="trendCol" mat-cell *matCellDef="let row">
          <div class="tooltip">
            <span class="userRecord">{{ column.cell(row) }}</span>
            <span class="tooltiptext">{{ column.cell(row) }}</span>
          </div>
        </td>
      </ng-container>
      <tr mat-header-row *matHeaderRowDef="dynamicColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: dynamicColumns"></tr>
    </table>
    <mat-paginator
    [pageSize]="6"
    [pageSizeOptions]="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20]"
    showFirstLastButtons
    >
    </mat-paginator>
    <div class="downloadDiv">
      Download as :
      <button style="margin:5px;" mat-raised-button (click)="exporter.exportTable('xlsx')">Excel</button>
      <button style="margin:5px;" mat-raised-button (click)="exporter.exportTable('csv')">Csv</button>
      <button style="margin:5px;" mat-raised-button (click)="exporter.exportTable('json')">Json</button>
      <button style="margin:5px;" mat-raised-button (click)="exporter.exportTable('txt')">Txt</button>
    </div>
  </ng-container>
</div>

TS

import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import {MatDialog} from '@angular/material/dialog';
import { Router } from '@angular/router';
import {BehaviorSubject} from 'rxjs';

@Component({
  selector: 'app-trends-list',
  templateUrl: './trends-list.component.html',
  styleUrls: ['./trends-list.component.scss'],
})
export class TrendsListComponent implements OnInit, AfterViewInit {
  
  index: number;
  id: string;

  dataChange: BehaviorSubject<TrendsForView[]> = new BehaviorSubject<TrendsForView[]>([]);
  
  public dataSource = new MatTableDataSource<TrendsForView>();

  globalFilter = '';

  @ViewChild(MatPaginator, {static: false})
  set paginator(value: MatPaginator) {
    this.dataSource.paginator = value;
  }
  
  columns: Array < {
    columnDef: string;
    header: string;
    cell: (element: any) => any;
  } > = [];
  dynamicColumns = ['actions', ...this.columns.map(c => c.columnDef)];
  searchValue = '';
  openId: number;
  constructor(private router: Router, private _router: Router,private trendsService: TrendsService, public dialog: MatDialog) {}

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

  onSearchChange(key: string) {
    this.dataSource.filter = JSON.stringify({key, value: this.searchValue.toLowerCase()});
  }
  closeSearch(key: string) {
    this.searchValue = '';
    this.dataSource.filter = JSON.stringify({key, value: this.searchValue.toLowerCase()});
  }

  customFilterPredicate() {
    const myFilterPredicate = (
      data: TrendsForView,
      filter: string
    ): boolean => {
      let searchString = JSON.parse(filter);
      if (this.searchValue) {
        return data[searchString.key].toString().trim().toLowerCase().indexOf(searchString.value) !== -1;
      } else {
        return true;
      }
     
    }
    return myFilterPredicate;
  }
  ngAfterViewInit(): void {
    this.dataSource.paginator = this.paginator;
  }
  public getTrends = () =>{
    this.trendsService.getTrend().subscribe((res) => {
      this.dataSource.data = res.all_docs;
    });
  };
  public getAllTrends = () => {
    this.trendsService.getTrend().subscribe((res) => {
      this.dataSource.data = res.all_docs;
      const columns = this.dataSource.data[0];
            if (columns) {
        Object.keys(columns).forEach((key) => {
          if(key!="unique_id"){
            this.columns.push({
              header: key.replace(/_/g, ' '),
              columnDef: key,
              cell: (element: any) => element[key]
            });
          }
        });
        this.dynamicColumns = ['actions', ...this.columns.map(c => c.columnDef)];
      }
    });
  };
  openFilterDynamic(index: number) {
    this.openId = (this.openId === index) ? undefined : index;
    this.closeSearch('')
  }

  public redirectToDetails = (id: string) => {
    this.router.navigate(['/home']);
  };

  navigateToTrendEdit(id: any){
    this._router.navigateByUrl('/home' + id);
  }

  deleteItem(id: any){
    this.openDialog(id);
  }

  openDialog(id: any) {
    const dialogRef = this.dialog.open(DeleteTrendDialogComponent,{
      data: {
        message: id
      }
    });

    dialogRef.afterClosed()
          .subscribe(result => {
            if (result === 'closed') {
              this.getTrends();
         }
          });


  }
}

正如我所说的单列搜索工作正常,但我被困在如何进行多列搜索。

【问题讨论】:

  • 默认情况下,角度材质会对多列进行过滤。 github.com/angular/components/blob/master/src/material/table/… 它将行中的所有值组合成一个字符串,然后尝试匹配您的过滤器字符串。
  • 是的,但是我的要求有点不同,我对每一列都有单独的搜索字段。如果我搜索一列并过滤数据并尝试从另一列搜索,则应从先前过滤的数据中过滤数据
  • 您可以存储最后的过滤器字符串并将其与新的过滤器字符串组合并传递给数据源的filterPredicate。
  • 你找到答案了吗

标签: angular typescript angular-material mat-table


【解决方案1】:

你试过 mat-table-filter 包吗?

例如,您需要有一个示例实体来表示您的过滤对象,当您填充它的属性时,表格会自动被过滤。

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

【讨论】:

    猜你喜欢
    • 2017-11-23
    • 1970-01-01
    • 2018-10-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-26
    • 2023-02-08
    • 1970-01-01
    相关资源
    最近更新 更多