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; } }
问题原因与解决方案
核心问题
- 自定义过滤规则被覆盖:在
ngOnInit中先设置了this.dataSource.filterPredicate,但获取后端数据后重新创建了MatTableDataSource实例,导致之前配置的过滤逻辑丢失,MatTable使用默认规则过滤,最终数据为空。 - 初始数据源状态异常:组件初始化时
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
相关产品推荐
相关产品推荐

