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

Angular嵌套Material表格行展开折叠异常:子行点击干扰外层行的解决

动态嵌套Material表格行展开/折叠异常修复

问题描述

在完全动态的嵌套Material表格中实现行展开折叠功能时,点击子行的展开按钮会触发外层行的展开/折叠状态变更,导致所有子内容联动,无法独立控制各层级的展开状态。

核心问题

当前代码中,子行点击事件直接修改了外层行的element.expanded状态,导致所有依赖该状态的子内容同步变化,没有为嵌套层级维护独立的展开状态。

修复方案

为每个嵌套分组添加独立的expanded属性,修改点击事件和状态绑定逻辑,确保各层级状态互不干扰。

修复后的完整代码

<div class="container">
  <table mat-table [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8">
    <ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns | async;">
      <th mat-header-cell *matHeaderCellDef class="text-Capitalise" [ngClass]=" column== 'subSection'?'noD':'disp' ">
        {{column && 
        column=='executionId'?'': column && 
        column=='createdBy'?'Created By': column && 
        column=='createdTs'?'Created Date': column && 
        column=='actualsMonth'?'Actual Month': column
        }}
      </th>
      <td mat-cell *matCellDef="let element;"
        [ngClass]="column== 'title'?'title-col':'disp' &&  
        column== 'description'?'description-col':'disp' &&  
        column== 'tags'?'tags-col':'disp' &&  
        column== 'subSection'?'noD':'disp'
        ">
       
        <span *ngIf="column=='executionId'">
          <mat-radio-button color="primary"></mat-radio-button>
        </span>
        <span *ngIf="column=='createdTs'">
          {{ element.section[column] | date  }}
        </span>
        <span class="section-head-text" matTooltip="{{element.section[column]}}">
          {{ element.section[column] && 
          column=='executionId'?'': element.section[column] &&
          column=='tags'?'': element.section[column]&&
          column=='createdTs'?'': element.section[column]
          }}
        </span>

        <span class="test-mat-chips" *ngIf="column=='tags'">
          <mat-chip-listbox>
            <span *ngFor="let symbols of element.section.tags">
              <mat-chip>{{symbols}} </mat-chip>
            </span>
          </mat-chip-listbox>
        </span>
      </td>
    </ng-container>

    <ng-container matColumnDef="expand">
      <th class="expand-column" *matHeaderCellDef aria-label="row actions">
        <button mat-icon-button aria-label="expand row" name='toggleButon'
        (click)="toggle(); $event.stopPropagation()">
        <mat-icon *ngIf="!allRowsExpanded">keyboard_arrow_down</mat-icon>
        <mat-icon *ngIf="allRowsExpanded">keyboard_arrow_up</mat-icon>
      </button>
      </th>
      <td class="expand-column" mat-cell *matCellDef="let element">
        <button mat-icon-button aria-label="expand row"
          (click)="(element.expanded = !element.expanded); $event.stopPropagation()">
          <mat-icon *ngIf="!element.expanded">keyboard_arrow_down</mat-icon>
          <mat-icon *ngIf="element.expanded">keyboard_arrow_up</mat-icon>
        </button>
      </td>
    </ng-container>

    <ng-container matColumnDef="expandedDetail">
      <td class="sub-grid-box" mat-cell *matCellDef="let element"
        [attr.colspan]="displayedColumnsWithExpand.value.length">

        <div *ngFor="let group of element.section.subSection ">
          <button class="grp-btn" mat-icon-button aria-label="expand row"
            (click)="(group.expanded = !group.expanded);$event.stopPropagation() ">
            <mat-icon *ngIf="!group.expanded">keyboard_arrow_down</mat-icon>
            <mat-icon *ngIf="group.expanded">keyboard_arrow_up</mat-icon>
          </button>
          <mat-card class="groupBy collapsible-group">
            <mat-card-content>
              {{group.groupBy.value}}
            </mat-card-content>
          </mat-card>

          <ng-container>
            <div *ngFor="let insgroup of group.groupBy.subSection"
              [@detailExpand]="(group.expanded)? 'expanded' : 'collapsed'" [hidden]="!group.expanded">
              <span class="collapsible-group-data"> {{insgroup.groupBy.value}}</span>
              <div>
                <app-sub-comp [gridData]="insgroup.groupBy.subSection"
                  [displayedColumns]="displayedColumnsWithExpand | async"></app-sub-comp>
              </div>
            </div>
          </ng-container>
        </div>
      </td>
    </ng-container>

    <ng-container>
      <tr mat-header-row *matHeaderRowDef="displayedColumnsWithExpand | async"></tr>
    </ng-container>
    <tr mat-row *matRowDef="let element; columns: displayedColumnsWithExpand | async; " class="element-row"
      [class.expanded-row]="element.expanded" (click)="toggleRow(element)">
    </tr>
    <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></tr>
  </table>
</div>

关键修改说明

  1. 独立状态维护:将子行点击事件从修改外层element.expanded改为修改当前分组的group.expanded,每个分组拥有独立的展开状态
  2. UI逻辑绑定:将展开动画[@detailExpand]和内容隐藏[hidden]逻辑绑定到group.expanded,确保仅当前分组的内容受影响
  3. 事件隔离:保留$event.stopPropagation()防止事件冒泡到外层行,避免误触发外层状态变更

内容的提问来源于stack exchange,提问作者Hitendra Singh Tomar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:34:59