如何基于接口数据用Angular Material创建动态双表头表格?
问题描述
想要创建如下所示的带动态详情列的表格:
| Level | 6 | 6 | 3 |
|---|---|---|---|
| Question | Comment | Comment | Comment |
| Q1 | 5 - 6 | 7 - 10 | |
| Q2 | 10 - 20 | 21 - 30 | |
| Q3 | 20 - 30 |
接口返回的数据格式如下:
[ { 'level' : 6, 'Question' : 'Q1', 'low' : 5, 'high' : 6 }, { 'level' : 6, 'Question' : 'Q1', 'low' : 7, 'high' : 10 }, { 'level' : 6, 'Question' : 'Q2', 'low' : 10, 'high' : 20 }, { 'level' : 6, 'Question' : 'Q2', 'low' : 21, 'high' : 30 }, { 'level' : 3, 'Question' : 'Q3', 'low' : 20, 'high' : 30 } ]
请问如何在Angular Material表格(mat table)中根据返回的数据实现上述带有动态列(如6、3等)的表格?
实现步骤
1. 数据预处理
首先需要把接口返回的扁平数据转换成适合表格展示的结构化数据,同时保留重复的level列(比如表格里的两个6列)。在组件的TypeScript代码中处理:
import { Component, OnInit } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; interface RawData { level: number; Question: string; low: number; high: number; } interface TableData { question: string; comments: { [key: string]: string }; } @Component({ selector: 'app-dynamic-table', templateUrl: './dynamic-table.component.html', styleUrls: ['./dynamic-table.component.css'] }) export class DynamicTableComponent implements OnInit { rawData: RawData[] = []; // 后续替换为接口返回数据 displayedColumns: string[] = ['question']; dynamicColumns: { id: string, label: string }[] = []; dataSource = new MatTableDataSource<TableData>([]); ngOnInit(): void { // 模拟接口请求,实际项目替换为HTTP请求 this.rawData = [ { level: 6, Question: 'Q1', low: 5, high: 6 }, { level: 6, Question: 'Q1', low: 7, high: 10 }, { level: 6, Question: 'Q2', low: 10, high: 20 }, { level: 6, Question: 'Q2', low: 21, high: 30 }, { level: 3, Question: 'Q3', low: 20, high: 30 } ]; this.processData(); } private processData(): void { // 按问题分组,收集每个问题的所有区间数据 const questionGroups = new Map<string, RawData[]>(); this.rawData.forEach(item => { if (!questionGroups.has(item.Question)) { questionGroups.set(item.Question, []); } questionGroups.get(item.Question)?.push(item); }); // 生成动态列:用索引做唯一ID,保留重复level的列 this.rawData.forEach((item, idx) => { const columnId = `level_col_${idx}`; this.dynamicColumns.push({ id: columnId, label: item.level.toString() }); this.displayedColumns.push(columnId); }); // 构造表格数据源 const tableData: TableData[] = []; questionGroups.forEach((items, question) => { const comments: { [key: string]: string } = {}; items.forEach(item => { const targetIdx = this.rawData.findIndex(raw => raw.Question === question && raw.low === item.low && raw.high === item.high ); if (targetIdx !== -1) { const columnId = `level_col_${targetIdx}`; comments[columnId] = `${item.low} - ${item.high}`; } }); tableData.push({ question, comments }); }); this.dataSource.data = tableData; } }
2. 编写HTML模板
用*ngFor渲染动态列,同时处理双层表头:
<div class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource"> <!-- 固定列:Question --> <ng-container matColumnDef="question"> <th mat-header-cell *matHeaderCellDef> <div>Level</div> <div><strong>Question</strong></div> </th> <td mat-cell *matCellDef="let element"> {{element.question}} </td> </ng-container> <!-- 动态列:每个Level对应的Comment列 --> <ng-container *ngFor="let col of dynamicColumns" [matColumnDef]="col.id"> <th mat-header-cell *matHeaderCellDef> <div>{{col.label}}</div> <div><strong>Comment</strong></div> </th> <td mat-cell *matCellDef="let element"> {{element.comments[col.id] || ''}} </td> </ng-container> <!-- 渲染表头和数据行 --> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> </div>
3. 样式优化(可选)
添加CSS让表头布局更美观:
.mat-header-cell div { text-align: center; line-height: 1.6; } .mat-cell { text-align: center; }
关键说明
- 用
Map按问题分组,确保每个问题只生成一行数据 - 动态列用索引拼接唯一ID,解决重复level列的标识冲突问题
- 数据源中通过列ID映射对应区间文本,渲染时直接取值即可
内容的提问来源于stack exchange,提问作者Ananthu
相关产品推荐
相关产品推荐

