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

如何使用Angular Mat-Table按列值透视展示数据?

问题描述

我有如下结构的数据源:

[{
    "testDisplayName": "Test_Name_1",
    "data": {
       "metrics": [
          {
            "metricValue": -0.18,
            "metricKey": "metricKey_1"
          },
          {
            "metricValue": 3.9,
            "metricKey": "metricKey_2"
          },
        ]
    },
    "url": "some_url",
    "revision": "rev1",
    "dId": "dId_1",
    "release": "release_1",
    "buildId": "build_1"
},
{
    "testDisplayName": "Test_Name_1",
    "data": {
       "metrics": [
          {
            "metricValue": -0.20,
            "metricKey": "metricKey_3"
          },
          {
            "metricValue": 3.8,
            "metricKey": "metricKey_4"
          },
        ]
    },
    "url": "url_2",
    "revision": "rev2",
    "dId": "dId_2",
    "release": "release_2",
    "buildId": "build_2"
}]

我希望用Angular Mat-Table将上述数据展示为如下表格形式:

build_1 release_1     build_2 release_2 => 这些是来自数据的动态值
                             
Metric Key     Metric value          Metric Value         => 静态列名

metricKey_1      -0.18                   3.9
metricKey_2      -0.20                   3.8

表格数据会根据testDisplayName进行过滤,不同的testDisplayName对应不同的metricKey和metricValue,例如当前过滤条件为Test_Name_1。

我的疑问是:这种需求能否通过Angular Mat-Table实现?因为我了解到Mat-Table不允许displayColumn中存在重复列名,也无法在单个单元格中展示两个数据值(如build_1 release_1),恳请提供帮助或指引,感谢!


解决方案

完全可以实现,核心是先转换数据源结构,再配合Mat-Table的动态列和多行表头功能处理:

1. 转换数据源

将原始数据转换成以metricKey为行标识、各构建版本的metricValue为列值的结构:

// 先过滤出目标testDisplayName的数据
const filteredData = originalData.filter(item => item.testDisplayName === 'Test_Name_1');

// 提取所有唯一的metricKey(合并所有条目里的metrics)
const allMetricKeys = Array.from(new Set(filteredData.flatMap(item => item.data.metrics.map(m => m.metricKey))));

// 构造表格最终数据源
this.tableDataSource = allMetricKeys.map(key => {
  const row: any = { metricKey: key };
  filteredData.forEach((item, index) => {
    // 匹配当前构建下对应metricKey的值,无匹配则设为null
    const metric = item.data.metrics.find(m => m.metricKey === key);
    row[`build_col_${index}`] = metric ? metric.metricValue : null;
  });
  return row;
});

2. 生成动态列配置

为每个构建版本生成唯一的列标识,同时记录表头显示文本:

// 初始化固定列+动态列集合
this.displayedColumns = ['metricKey'];
this.buildColumnConfigs = filteredData.map((item, index) => {
  const columnKey = `build_col_${index}`;
  this.displayedColumns.push(columnKey);
  return {
    key: columnKey,
    headerText: `${item.buildId} ${item.release}` // 合并buildId和release作为表头
  };
});

3. 模板中实现表格

通过多行表头解决分组展示需求,用动态列处理不同构建版本的数据:

<table mat-table [dataSource]="tableDataSource" class="mat-elevation-z8">
  <!-- 第一行表头:构建版本信息 -->
  <ng-container matHeaderRowDef="buildHeaderRow">
    <tr mat-header-row>
      <th mat-header-cell></th>
      <th mat-header-cell *ngFor="let col of buildColumnConfigs">
        {{ col.headerText }}
      </th>
    </tr>
  </ng-container>

  <!-- 第二行表头:静态列名 -->
  <ng-container matHeaderRowDef="staticHeaderRow">
    <tr mat-header-row>
      <th mat-header-cell>Metric Key</th>
      <th mat-header-cell *ngFor="let col of buildColumnConfigs">Metric Value</th>
    </tr>
  </ng-container>

  <!-- Metric Key固定列 -->
  <ng-container matColumnDef="metricKey">
    <td mat-cell *matCellDef="let element">{{ element.metricKey }}</td>
  </ng-container>

  <!-- 动态构建列 -->
  <ng-container *ngFor="let col of buildColumnConfigs" [matColumnDef]="col.key">
    <td mat-cell *matCellDef="let element">{{ element[col.key] }}</td>
  </ng-container>

  <!-- 表格数据行 -->
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>

  <!-- 渲染两行表头 -->
  <tr mat-header-row *matHeaderRowDef="['buildHeaderRow', 'staticHeaderRow']; sticky: true"></tr>
</table>

关键说明

  • 重复列名问题:通过生成唯一的列标识(如build_col_0、build_col_1)解决,Mat-Table仅要求matColumnDef的值唯一,表头显示文本可重复。
  • 单元格多值展示:直接在模板中拼接buildId和release作为表头文本,无需特殊处理。
  • 适配不同testDisplayName:切换过滤条件时,重新执行数据源转换和列配置生成逻辑即可更新表格。

内容的提问来源于stack exchange,提问作者Kishore Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:46:08