【问题标题】:Correctly display in a mat-table a data list grouped with dynamic columns在 mat-table 中正确显示与动态列分组的数据列表
【发布时间】:2020-11-12 00:23:07
【问题描述】:

我有一个很遗憾无法解决的问题。

我的 API 向我返回如下数据列表:

[
  {grade: "Grade A", id: 1, ifsGrade: "A1XX", ifsType: "01XX", points: 22, type: "Type_1"},
  {grade: "Grade B", id: 2, ifsGrade: "B1XX", ifsType: "02XX", points: 15, type: "Type_1"},
  {grade: "Grade C", id: 3, ifsGrade: "C1XX", ifsType: "03XX", points: 1,  type: "Type_1"},
  {grade: "Grade A", id: 4, ifsGrade: "A2XX", ifsType: "04XX", points: 23, type: "Type_2"},
  {grade: "Grade B", id: 5, ifsGrade: "B2XX", ifsType: "05XX", points: 26, type: "Type_2"}
]

我按类型对我的数据进行分组,如下所示:

Array.prototype.groupBy = function(k) {
   return this.reduce((acc, item) => (acc[item[k]] = [...(acc[item[k]] || []), item], acc), {});
};

var TABLE_DATA = Object.values(API_DATA.groupBy("type"));

[
  [
    {grade: "Grade A", id: 1, ifsGrade: "A1XX", ifsType: "01XX", points: 22, type: "Type_1"},
    {grade: "Grade B", id: 2, ifsGrade: "B1XX", ifsType: "02XX", points: 15, type: "Type_1"},
    {grade: "Grade C", id: 3, ifsGrade: "C1XX", ifsType: "03XX", points: 1,  type: "Type_1"}
  ],
  [
    {grade: "Grade A", id: 4, ifsGrade: "A2XX", ifsType: "04XX", points: 23, type: "Type_2"},
    {grade: "Grade B", id: 5, ifsGrade: "B2XX", ifsType: "05XX", points: 26, type: "Type_2"}
  ]
]

我希望能够在 Angular Material mat-table 中显示数据,如下所示:

所以我的数据源确实有一个列表,但这个列表的元素也是列表。所以我不知道如何正确显示项目。

所以对于表格列,您需要像这样的动态,但我不知道如何:

<ng-container matColumnDef="{{column}}" *ngFor="let column of definedColumns">
  <th mat-header-cell *matHeaderCellDef> {{column}} </th>
  <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
</ng-container>

Stackblitz 链接 here

感谢您的帮助

【问题讨论】:

标签: json angular typescript angular-material mat-table


【解决方案1】:

您需要遍历数据并将不同的值映射到新对象。

这是一个工作堆栈示例 https://stackblitz.com/edit/datasource-mat-table-with-group-by-ay2rbh

以及来自stackblitz的相关函数

  convertedData: ElementType[];

  // creates "gradeX" from "Grade X"
  convertGradeToGradeKey(grade: string): string{
    return `grade${grade.split(" ")[1]}`;
  }

  // probably worth typing this "data" properly as well...
  mapDataFromApi(data: any[]): void {
  // using a map so we don't have to iterate the whole list to find type === "someType" every time
  let mappedData = new Map<string, ElementType>();
   
   data.forEach(val => {
     // get the existing value from the map, or ceate a "new" one if its not there
     let currentVal = mappedData.get(val.type) || {type: val.type, gradeA: undefined, gradeB: undefined, gradeC: undefined};
     // get the "grade key" from the string value
     const gradeKey = this.convertGradeToGradeKey(val.grade);
     // get the new value, which will be the curent value + this row's "poiints"
     const newGradeValue: number = (currentVal[gradeKey] || 0) + val.points;
     // merge the current value object with the new property
     currentVal = {...currentVal, [gradeKey]: newGradeValue };
     // add upate the value in the set
     mappedData.set(val.type, currentVal);
   })
   // create a normal array from that mapped data
   this.convertedData = [...mappedData].map(([key, val]) => val);
  }

【讨论】:

  • 谢谢你的回答,我修改了我的帖子。我不想修改我的对象,因为我需要所有属性来修改或删除它们。所以我找到了一个解决方案,可以在列表中按类型对它们进行分组。但是表格中的显示比较复杂
  • 对不起,我真的不明白你现在在更新中想要做什么。如果要在表格中显示数据,它需要是单个数组。您最初发布的是汇总表,但现在我不确定它是什么。
  • 如果你想在你想要的表格中显示它们,你需要像我一样做一些事情。如果您查看我的 stackblitz,我不会修改原始数据,如果您需要更新原始数据,原始数据仍在不同的变量中。不确定您的添加/删除按钮会做什么,因为该行不知道您要更新哪个原始值
  • 你的表中显示的数据不具备所有原始属性(id、ifsType ...)。我将需要它来编辑和删除,因为数据库中的几行会受到影响。
  • 这就是为什么我这次修改了我的帖子,将我的数据按“类型”分组。因此,表格的每一行都是一个数据列表,但只有某些值应该显示在正确的列中。在我想修改行时发布的答案中,我将检索与类型对应的所有数据的列表,以便能够修改或删除它们。
【解决方案2】:

按type 分组的数据初始化:

ngOnInit() {
    this.API_DATA = [
      {grade: "Grade A", id: 1, ifsGrade: "A1XX", ifsType: "01XX", points: 22, type: "Type_1"},
      {grade: "Grade B", id: 2, ifsGrade: "B1XX", ifsType: "02XX", points: 15, type: "Type_1"},
      {grade: "Grade C", id: 3, ifsGrade: "C1XX", ifsType: "03XX", points: 1,  type: "Type_1"},
      {grade: "Grade A", id: 4, ifsGrade: "A2XX", ifsType: "04XX", points: 23, type: "Type_2"},
      {grade: "Grade B", id: 5, ifsGrade: "B2XX", ifsType: "05XX", points: 16, type: "Type_2"}
    ];

    const key = 'type'
    const dataTable = Object.values(this.API_DATA.reduce((acc, item) => (acc[item[key]] = [...(acc[item[key]] || []), item], acc), {}));

    this.dataSource = dataTable;
  }

mat-table Angular 材质与动态列:

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
  
  <ng-container matColumnDef="{{column}}" *ngFor="let column of definedColumns; let index = index;">
    <th mat-header-cell *matHeaderCellDef> {{column}} </th>
    <td mat-cell *matCellDef="let elements">
      <span *ngFor="let element of elements; let first = first;">
        <span *ngIf="index == 0 && first">{{element.type}}</span>
        <span *ngIf="element.grade == column">{{element.points}}</span>
      </span>
    </td>
  </ng-container>

  <ng-container matColumnDef="action">
    <th mat-header-cell *matHeaderCellDef class="text-right">
        <button mat-icon-button (click)="log('add')">
            <mat-icon color="accent">add_circle_outline</mat-icon>
        </button>
    </th>
    <td mat-cell *matCellDef="let gradingIndex" class="text-right">
        <button mat-icon-button>
            <mat-icon color="primary" (click)="log(gradingIndex)">edit</mat-icon>
        </button>
        <button mat-icon-button (click)="log(gradingIndex)">
            <mat-icon color="warn">delete</mat-icon>
        </button>
    </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

结果:

Stackblitz : here

【讨论】:

    猜你喜欢
    • 2020-11-20
    • 2022-12-09
    • 2020-03-23
    • 2018-03-25
    • 2021-09-05
    • 2021-02-25
    • 1970-01-01
    • 2021-12-29
    • 2017-10-05
    相关资源
    最近更新 更多