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

嵌套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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 10:08:10