多标签页表格排序时ngAfterViewInit未触发,matSort失效求助
MatSort在Angular标签页组件中无法正常工作
问题场景
现有三个组件:主组件approve-home和两个标签页组件approve-main、approve-group。切换到第二个标签页approve-group后,表格的matSort功能完全失效,点击排序表头无任何反应。排查发现ngAfterViewInit仅在组件首次启动时触发,触发时间早于切换到该标签页的操作。
相关代码
approve-home.component.ts
@Component({ selector: 'app-approve-home', templateUrl: './approve-home.component.html', styleUrls: ['./approve-home.component.css'] }) export class ApproveHomeComponent implements OnInit { @ViewChild('tabGroup', {static: false}) tabGroup: MatTabGroup; constructor() { } ngOnInit() { } onMoveTab(event: { tabIndex: number }) { this.tabGroup.selectedIndex = event.tabIndex; } }
approve-home.component.html
<mat-tab-group #tabGroup class="tab-hide"> <mat-tab label="To be hidden"> <app-approve-main (moveTab)="onMoveTab($event)"></app-approve-main> </mat-tab> <mat-tab label="To be hidden"> <app-approve-group (moveTab)="onMoveTab($event)"></app-approve-group> </mat-tab> </mat-tab-group>
approve-group.component.ts
displayedColumns: string[] = ['applicationNo', 'surname', 'otherNames', 'dob', 'tdType', 'previousTDNo', 'action']; dataSource = new MatTableDataSource<TdApplication>([]); @ViewChild(MatSort, {static: true}) sort: MatSort; @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; @Output() moveTab = new EventEmitter<{ tabIndex: number }>(); ngAfterViewInit(): void { this.dataSource.sortingDataAccessor = (tdApps, property) => { switch (property) { case 'applicationNo': console.log(property); return tdApps.applicationNo ? tdApps.applicationNo.toLocaleLowerCase() : ''; case 'surname': return tdApps.applicantDetails.surname.toLocaleLowerCase(); case 'otherNames': return tdApps.applicantDetails.otherName.toLocaleLowerCase(); case 'dob': return tdApps.applicantDetails.dob.toString(); case 'tdType': return tdApps.applicantDetails.tdType && tdApps.applicantDetails.tdType.documentType ? tdApps.applicantDetails.tdType.documentType.name.toLocaleLowerCase() : ''; case 'previousTDNo': return tdApps.applicantDetails.prevTdNo && tdApps.applicantDetails.prevTdNo.length > 0 ? tdApps.applicantDetails.prevTdNo.toLocaleLowerCase() : ''; default: // @ts-ignore return tdApps[property]; } }; this.dataSource.sort = this.sort; }
approve-group.component.html
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8" matSort> <!-- Application No Column --> <ng-container matColumnDef="applicationNo"> <th mat-header-cell *matHeaderCellDef mat-sort-header> Application No </th> <td mat-cell *matCellDef="let element"> {{element?.applicationNo}} </td> </ng-container>
注意:所有导入均已正确配置
问题原因
- MatTabGroup的DOM渲染特性:未激活的标签页内容会被设置为
display: none,虽然组件已初始化,但MatSort的交互事件未正确绑定到数据源,导致点击表头无响应。 - static属性设置问题:
@ViewChild(MatSort, {static: true})会在组件初始化早期获取实例,此时标签页DOM尚未完全渲染,导致sort实例与数据源的关联失效。
解决方案
方案1:调整MatSort的ViewChild获取方式
将static: true改为static: false,确保在视图完全渲染后获取MatSort实例:
@ViewChild(MatSort, {static: false}) sort: MatSort;
方案2:监听标签页激活事件,重新绑定Sort
在主组件中监听标签页切换事件,当切换到目标标签页时,通知子组件重新绑定Sort:
- 修改
approve-home.component.html,添加标签切换事件:
<mat-tab-group #tabGroup class="tab-hide" (selectedTabChange)="onTabChange($event)"> <!-- 原有标签内容不变 --> </mat-tab-group>
- 在
approve-home.component.ts中添加事件处理逻辑:
import { ApproveGroupComponent } from './approve-group/approve-group.component'; // ... @ViewChild(ApproveGroupComponent) approveGroup: ApproveGroupComponent; onTabChange(event: MatTabChangeEvent) { // 第二个标签页的索引为1,根据实际情况调整 if (event.index === 1) { this.approveGroup.rebindSort(); } }
- 在
approve-group.component.ts中添加rebindSort方法:
rebindSort() { this.dataSource.sort = this.sort; // 手动触发数据源更新,确保排序逻辑生效 this.dataSource._updateChangeSubscription(); }
方案3:启用标签页懒加载
给目标标签页添加lazyLoad属性,确保组件在首次激活时才初始化,此时ngAfterViewInit会在标签页显示后执行:
<mat-tab label="To be hidden" lazyLoad> <app-approve-group (moveTab)="onMoveTab($event)"></app-approve-group> </mat-tab>
验证
完成上述任意一种修改后,切换到第二个标签页,点击排序表头,控制台应输出对应的property值,表格数据会按指定规则排序。
内容的提问来源于stack exchange,提问作者Ashrik Ahamed
相关产品推荐
相关产品推荐

