You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular MatTable多列筛选异常:过滤后数据为空且无控制台报错

Angular MatTable多列过滤失效问题解决

我尝试在Angular的MatTable中实现多列过滤功能——列头的文本输入框仅对对应列内容进行过滤。目前针对client_name和module_control列做了尝试,但功能失效:过滤后数据数组变为空,控制台无任何报错信息。

原代码

home.component.html

<table mat-table [dataSource]="dataSource" matSort>

  <ng-container matColumnDef="module_control">
    <th mat-header-cell *matHeaderCellDef >Module control
      <div>
        <mat-form-field>
          <input matInput class="form-field" [formControl]="moduleControlFilter" placeholder="Filter" (click)="$event.stopPropagation()"/>
        </mat-form-field>
      </div>
    </th>
    <td mat-cell *matCellDef="let element"> {{element.module_control}} </td>
  </ng-container>

  <ng-container matColumnDef="client_name">
    <th mat-header-cell *matHeaderCellDef >Client name
      <div>
        <mat-form-field>
          <input matInput class="form-field" [formControl]="clientNameFilter" placeholder="Filter" (click)="$event.stopPropagation()"/>
        </mat-form-field>
      </div>
    </th>
    <td mat-cell *matCellDef="let element"> {{element.client_name}} </td>
  </ng-container>

      ......

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

Home.component.ts

export class HomeComponent implements OnInit {

  displayedColumns: string[] = ['module_control', "client_name"];
  customers!: Customer[];

  dataSource = new MatTableDataSource<Customer>(this.customers)

  clientNameFilter = new FormControl();
  moduleControlFilter = new FormControl();

  filteredValues = { 
    client_name: '',
    module_control: '',
  }

  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) matSort! : MatSort;

  constructor(private customerService: customerService) { }

  ngOnInit() {
    this.moduleControlFilter.valueChanges.subscribe((moduleControlFilterValue) => {
      this.filteredValues['module_control'] = moduleControlFilterValue;
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });

    this.clientNameFilter.valueChanges.subscribe((ClientNameFilterValue) => {
      this.filteredValues['client_name'] = ClientNameFilterValue;
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });


    this.dataSource.filterPredicate = this.filterTable()

    this.customerService.getAllCustomers().subscribe(
      customers => {
        this.customers = customers;
        this.dataSource = new MatTableDataSource<Customer>(this.customers);
        this.dataSource.paginator = this.paginator;
      },
      (error: HttpErrorResponse) => {
        console.log(error.message);
      })
  }

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

  filterTable() {
    const myFilterPredicate = function(data: Customer, filter: string): boolean 
    {
      let searchString = JSON.parse(filter);
      return (
        data?.module_control?.toString().trim().toLowerCase().indexOf(searchString.module_control.toLowerCase()) !== -1 &&
        data?.client_name?.toString().trim().toLowerCase().indexOf(searchString.client_name.toLowerCase()) !== -1
      );
    };
    return myFilterPredicate;
  }
}

问题原因与解决方案

核心问题

  1. 自定义过滤规则被覆盖:在ngOnInit中先设置了this.dataSource.filterPredicate,但获取后端数据后重新创建了MatTableDataSource实例,导致之前配置的过滤逻辑丢失,MatTable使用默认规则过滤,最终数据为空。
  2. 初始数据源状态异常:组件初始化时this.customers未赋值,初始dataSource指向undefined,若在数据加载完成前操作过滤框,会基于空数据过滤。

修正步骤

1. 保留同一个数据源实例

不要重新创建MatTableDataSource,直接更新现有实例的data属性:

this.customerService.getAllCustomers().subscribe(
  customers => {
    this.customers = customers;
    // 替换重新创建数据源的操作
    this.dataSource.data = this.customers;
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.matSort;
    // 数据加载完成后触发一次过滤,确保条件生效
    this.dataSource.filter = JSON.stringify(this.filteredValues);
  },
  (error: HttpErrorResponse) => {
    console.log(error.message);
  })

2. 优化过滤逻辑(可选)

将过滤逻辑改为更直观的写法,同时提前处理空值情况:

filterTable() {
  const myFilterPredicate = (data: Customer, filter: string): boolean => {
    const searchString = JSON.parse(filter);
    // module_control列过滤:为空则不过滤,否则匹配包含关系
    const moduleMatch = !searchString.module_control || 
      data?.module_control?.toString().trim().toLowerCase().includes(searchString.module_control.toLowerCase());
    // client_name列过滤:为空则不过滤,否则匹配包含关系
    const clientMatch = !searchString.client_name || 
      data?.client_name?.toString().trim().toLowerCase().includes(searchString.client_name.toLowerCase());
    // 两列条件同时满足才显示数据
    return moduleMatch && clientMatch;
  };
  return myFilterPredicate;
}

3. 移除无用代码

删除未使用且逻辑重复的applyFilter函数,同时将初始数据源改为空数组避免undefined:

// 替换原来的初始化代码
dataSource = new MatTableDataSource<Customer>([]);

完整修正后的Home.component.ts

export class HomeComponent implements OnInit {
  displayedColumns: string[] = ['module_control', 'client_name'];
  customers!: Customer[];

  dataSource = new MatTableDataSource<Customer>([]);

  clientNameFilter = new FormControl();
  moduleControlFilter = new FormControl();

  filteredValues = { 
    client_name: '',
    module_control: '',
  };

  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) matSort!: MatSort;

  constructor(private customerService: customerService) { }

  ngOnInit() {
    // 设置自定义过滤规则
    this.dataSource.filterPredicate = this.filterTable();

    // 监听module_control过滤框变化
    this.moduleControlFilter.valueChanges.subscribe((moduleControlFilterValue) => {
      this.filteredValues['module_control'] = moduleControlFilterValue.trim().toLowerCase();
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });

    // 监听client_name过滤框变化
    this.clientNameFilter.valueChanges.subscribe((clientNameFilterValue) => {
      this.filteredValues['client_name'] = clientNameFilterValue.trim().toLowerCase();
      this.dataSource.filter = JSON.stringify(this.filteredValues);
    });

    // 获取后端数据
    this.customerService.getAllCustomers().subscribe(
      customers => {
        this.customers = customers;
        this.dataSource.data = this.customers;
        this.dataSource.paginator = this.paginator;
        this.dataSource.sort = this.matSort;
        // 触发一次过滤,确保初始状态正确
        this.dataSource.filter = JSON.stringify(this.filteredValues);
      },
      (error: HttpErrorResponse) => {
        console.log(error.message);
      });
  }

  filterTable() {
    const myFilterPredicate = (data: Customer, filter: string): boolean => {
      const searchString = JSON.parse(filter);
      const moduleMatch = !searchString.module_control || 
        data?.module_control?.toString().trim().toLowerCase().includes(searchString.module_control);
      const clientMatch = !searchString.client_name || 
        data?.client_name?.toString().trim().toLowerCase().includes(searchString.client_name);
      return moduleMatch && clientMatch;
    };
    return myFilterPredicate;
  }
}

内容的提问来源于stack exchange,提问作者Daemes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 18:35:28