Angular项目中MatTable绑定API数据后按名称过滤功能失效求助
Angular MatTable 名称过滤失效问题修复方案
核心问题排查
- API返回值类型定义错误:你调用的接口返回的是用户数组,原有代码定义的返回类型为单个Element对象,类型不匹配
- 异步数据加载逻辑顺序错误:
formSubscribe()和getFormsValue()在API请求返回前就绑定到了初始的空dataSource上,API返回后你重新实例化了新的MatTableDataSource,之前绑定的过滤规则、表单值变更监听都没有作用到新的数据源上 - 过滤逻辑缺少空值边界处理:搜索值为空时可能出现匹配异常
- HTML模板存在冗余代码:select列外有多余的
*matCellDef="let element"代码,可能引发编译警告
具体修复步骤
1. 修正 api-service.service.ts 的返回类型
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http' export interface Element { id: number; name: string; username: string; email: string; } @Injectable({ providedIn: 'root' }) export class ApiServiceService { constructor(private http: HttpClient) { } // 修正返回类型为Element数组 getRandomUsers(): Observable<Element[]> { const URL = 'https://jsonplaceholder.typicode.com/users'; return this.http.get<Element[]>(URL); } }
2. 调整 persons.ts 逻辑顺序与过滤逻辑
不要重新实例化MatTableDataSource,直接修改数据源的data属性,保留已绑定的过滤规则:
import { Component, OnInit, ViewChild } from '@angular/core'; import { FormGroup, FormControl } from '@angular/forms' import { MatTableDataSource } from '@angular/material/table'; import { ApiServiceService, Element } from './api-service.service' import { Subscription } from 'rxjs/internal/Subscription'; // 若使用分页需引入MatPaginator import { MatPaginator } from '@angular/material/paginator'; @Component({ selector: 'app-persons', templateUrl: './persons.component.html', styleUrls: ['./persons.component.css'] }) export class PersonsComponent implements OnInit { private subs = new Subscription(); private dataArray: Element[] = []; dataSource = new MatTableDataSource<Element>() // 绑定分页组件 @ViewChild(MatPaginator) paginator!: MatPaginator; constructor(private financeService: ApiServiceService) { } displayedColumns: string[] = ['position', 'name', 'username', 'email', 'action']; filterValues = { name: '' }; filterForm = new FormGroup({ name: new FormControl('') }); get name() { return this.filterForm.get('name'); } ngOnInit() { // 先绑定过滤规则和表单监听,只执行一次 this.formSubscribe(); this.getFormsValue(); this.subs.add(this.financeService.getRandomUsers() .subscribe((res) => { this.dataArray = res; // 直接给data赋值,不重新实例化数据源,保留已绑定的过滤规则 this.dataSource.data = this.dataArray; // 绑定分页 this.dataSource.paginator = this.paginator; }) ); } formSubscribe() { if (this.name != null) { this.name.valueChanges.subscribe(nameValue => { this.filterValues['name'] = nameValue || ''; this.dataSource.filter = JSON.stringify(this.filterValues); }); } } getFormsValue() { this.dataSource.filterPredicate = (data: Element, filter: string): boolean => { let searchString = JSON.parse(filter); // 搜索值为空时返回所有数据 if (!searchString.name) return true; const searchKey = searchString.name.trim().toLowerCase(); return data.name.trim().toLowerCase().indexOf(searchKey) !== -1; }; this.dataSource.filter = JSON.stringify(this.filterValues); } // 组件销毁时取消订阅避免内存泄漏 ngOnDestroy() { this.subs.unsubscribe(); } }
3. 清理HTML模板冗余代码
删除select列下多余的*matCellDef="let element"代码即可,其余代码无需修改。
修复后在搜索框输入名称关键词即可触发过滤,输入为空时展示全部数据,分页功能也可正常使用。
内容的提问来源于stack exchange,提问作者H Jafari
相关产品推荐
相关产品推荐

