嵌套Mat-Table搜索问题:清空输入后数据无法恢复初始状态
问题分析
你遇到的核心问题是过滤时直接修改了原始数据对象的addresses属性,将原本的数组替换成了过滤后的MatTableDataSource,导致清空搜索框时没有原始数据可以恢复。比如搜索"Ohio"时,Jason的addresses被替换为只包含匹配项的数据源,清空后无法还原回初始的2条地址数据。
解决方案
核心思路是保留原始数据副本,过滤时不修改原始数据对象,通过临时属性处理嵌套表格的显示逻辑。
1. 保存原始数据副本
在组件初始化时,深拷贝一份原始用户数据,确保后续操作不会污染原始数据:
originalUsers: User[] = []; ngOnInit() { // 假设你的初始用户数据是this.users this.originalUsers = JSON.parse(JSON.stringify(this.users)); this.dataSource = new MatTableDataSource(this.users); }
2. 修复清空过滤逻辑
当搜索框清空时,恢复数据源为原始数据,同时重置展开状态:
searchFilter = ''; // 保存当前搜索值,用于嵌套表格过滤 applyFilter(filterValue: string) { this.searchFilter = filterValue.trim().toLowerCase(); if (!this.searchFilter) { // 恢复原始数据(深拷贝避免后续修改影响原始数据) this.dataSource.data = JSON.parse(JSON.stringify(this.originalUsers)); this.dataSource.filter = ''; this.expandedElement = null; return; } // 定义过滤规则:仅判断匹配,不修改原始数据 this.dataSource.filterPredicate = (data: User, filter: string) => { // 检查用户自身字段是否匹配 const userFieldMatch = data.name.toLowerCase().includes(filter) || data.email.toLowerCase().includes(filter) || data.phone.toLowerCase().includes(filter); if (userFieldMatch) return true; // 检查地址字段是否匹配 if (data.addresses && Array.isArray(data.addresses)) { return (data.addresses as Address[]).some(address => address.street.toLowerCase().includes(filter) || address.zipCode.toLowerCase().includes(filter) || address.city.toLowerCase().includes(filter) ); } return false; }; this.dataSource.filter = this.searchFilter; // 自动展开第一个匹配的行 if (this.dataSource.filteredData.length > 0) { this.expandedElement = this.dataSource.filteredData[0]; this.toggleRow(this.expandedElement); } }
3. 修改行展开逻辑,不污染原始数据
给User接口新增临时属性filteredAddresses,用于存储嵌套表格的过滤后数据源:
interface User { name: string; email: string; phone: string; addresses: Address[]; filteredAddresses?: MatTableDataSource<Address>; // 临时存储过滤后地址 }
然后修改toggleRow方法:
toggleRow(element: User) { const isExpanded = this.expandedElement === element; this.expandedElement = isExpanded ? null : element; if (!isExpanded && element.addresses && Array.isArray(element.addresses)) { let targetAddresses = element.addresses as Address[]; // 根据当前搜索值过滤嵌套表格数据 if (this.searchFilter) { const filter = this.searchFilter.toLowerCase(); targetAddresses = targetAddresses.filter(address => address.street.toLowerCase().includes(filter) || address.zipCode.toLowerCase().includes(filter) || address.city.toLowerCase().includes(filter) ); } // 给元素设置临时的过滤后数据源 element.filteredAddresses = new MatTableDataSource(targetAddresses); this.cd.detectChanges(); // 给嵌套表格设置排序 this.innerTables.forEach((table, index) => { (table.dataSource as MatTableDataSource<Address>).sort = this.innerSort.toArray()[index]; }); } }
4. 更新模板中的嵌套表格数据源
将嵌套表格的dataSource改为优先使用临时的filteredAddresses,无过滤时使用原始addresses数组:
<mat-table #innerTable [dataSource]="element.filteredAddresses || element.addresses"> <!-- 嵌套表格列定义 --> </mat-table>
效果说明
- 搜索时,会匹配用户字段或地址字段,自动展开第一个匹配行并显示过滤后的嵌套地址数据
- 清空搜索框后,主表格和嵌套表格都会完全恢复到初始状态
内容的提问来源于stack exchange,提问作者Teja
相关产品推荐
相关产品推荐

