Angular Material如何渲染多层嵌套对象内的数组数据到表格
核心问题
你当前的代码有三处核心错误导致嵌套数据无法渲染:
- 模型定义和接口返回不匹配:你在
Month类中把compteurFDP/prisesDuMois/compteurFinDuMois定义为数组,但db.json里返回的是单个对象,调用.length会直接返回undefined,遍历逻辑全失效 - 数据展平逻辑错误:你当前的reduce逻辑没有把每个月份下的三类子数据(期初、当月消耗、期末)和列对应上,导致单元格取不到值
- 表头列定义不匹配:你要实现的是月份下分三类子指标的多层表头,当前的列定义没有对应这三层结构,和你写的colspan分组也对不上
修复步骤
第一步:修正模型定义
把Month类里的数组类型改成单个对象,和接口返回对齐:
export class Month { month!: string; compteurFDP!: compteurFDP; // 去掉Array声明,改为单个对象 prisesDuMois!: prisesDuMois; compteurFinDuMois!: compteurFinDuMois; }
第二步:修正TS中的数据处理逻辑
把原来错误的reduce逻辑替换成按月份+指标类型拼接列名的展平逻辑,同时补全所有显示列:
// 定义每个月份下要显示的三类指标映射规则 const MONTH_SUB_KEYS = [ {suffix: '_fdp_cp', label: 'CP', group: 'Cpteur FDP'}, {suffix: '_fdp_rtts', label: 'RTTS', group: 'Cpteur FDP'}, {suffix: '_fdp_rtte', label: 'RTTE', group: 'Cpteur FDP'}, {suffix: '_prise_cp', label: 'CP', group: 'Prises du mois'}, {suffix: '_prise_rtts', label: 'RTTS', group: 'Prises du mois'}, {suffix: '_prise_rtte', label: 'RTTE', group: 'Prises du mois'}, {suffix: '_fin_cp', label: 'CP', group: 'Cpteur fin de mois'}, {suffix: '_fin_rtts', label: 'RTTS', group: 'Cpteur fin de mois'}, {suffix: '_fin_rtte', label: 'RTTE', group: 'Cpteur fin de mois'}, {suffix: '_fin_somme', label: 'Somme', group: 'Cpteur fin de mois'}, ] displayedColumns: string[] = [ 'collaborator', 'cetCP', 'cetRTT', 'perteRTT', 'perteCP' ]; // 存储所有动态生成的月份子列配置 monthSubColumns: {colKey: string, month: string, label: string, group: string}[] = []; ngOnInit(): void { this.reportingService.getNews().subscribe( (response: visionCompacteDTOs[]) => { if (!response) return; // 生成所有月份子列配置 const months = response[0].mnth; months.forEach(m => { MONTH_SUB_KEYS.forEach(k => { const colKey = `${m.month}${k.suffix}`; this.monthSubColumns.push({ colKey, month: m.month, label: k.label, group: k.group }) this.displayedColumns.push(colKey); }) }) // 展平嵌套数据,和列名一一对应 this.dataSource = response.map(data => { const flatObj: any = {...data}; data.mnth.forEach(m => { // 赋值期初值 flatObj[`${m.month}_fdp_cp`] = m.compteurFDP.cp; flatObj[`${m.month}_fdp_rtts`] = m.compteurFDP.rtts; flatObj[`${m.month}_fdp_rtte`] = m.compteurFDP.rtte; // 赋值当月消耗值 flatObj[`${m.month}_prise_cp`] = m.prisesDuMois.cp; flatObj[`${m.month}_prise_rtts`] = m.prisesDuMois.rtts; flatObj[`${m.month}_prise_rtte`] = m.prisesDuMois.rtte; // 赋值期末值 flatObj[`${m.month}_fin_cp`] = m.compteurFinDuMois.cp; flatObj[`${m.month}_fin_rtts`] = m.compteurFinDuMois.rtts; flatObj[`${m.month}_fin_rtte`] = m.compteurFinDuMois.rtte; flatObj[`${m.month}_fin_somme`] = m.compteurFinDuMois.somme; }) return flatObj; }) }, error => console.log('Error Occured: ' + error) ); }
第三步:修正HTML渲染逻辑
按多层表头结构渲染,可根据你需要的层级调整colspan分组逻辑:
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8 lftm"> <!-- 固定列定义 --> <ng-container matColumnDef="collaborator"> <th mat-header-cell *matHeaderCellDef> 员工 </th> <td mat-cell *matCellDef="let element"> {{element.collaborator}} </td> </ng-container> <ng-container matColumnDef="cetCP"> <th mat-header-cell *matHeaderCellDef > CP </th> <td mat-cell *matCellDef="let element"> {{element.cetCP}} </td> </ng-container> <ng-container matColumnDef="cetRTT"> <th mat-header-cell *matHeaderCellDef > RTT </th> <td mat-cell *matCellDef="let element"> {{element.cetRTT}} </td> </ng-container> <ng-container matColumnDef="perteRTT"> <th mat-header-cell *matHeaderCellDef > 损失RTT </th> <td mat-cell *matCellDef="let element"> {{element.perteRTT}} </td> </ng-container> <ng-container matColumnDef="perteCP"> <th mat-header-cell *matHeaderCellDef> 损失CP </th> <td mat-cell *matCellDef="let element"> {{element.perteCP}} </td> </ng-container> <!-- 动态生成月份子列定义 --> <ng-container *ngFor="let col of monthSubColumns" [matColumnDef]="col.colKey"> <th mat-header-cell *matHeaderCellDef> {{col.label}} </th> <td mat-cell *matCellDef="let element"> {{element[col.colKey]}} </td> </ng-container> <!-- 多层表头+内容行定义 --> <tr mat-header-row *matHeaderRowDef="['collaborator', 'cetCP', 'cetRTT', 'perteRTT', 'perteCP', ...monthSubColumns.map(c=>c.colKey)]"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table>
内容的提问来源于stack exchange,提问作者adam
相关产品推荐
相关产品推荐

