没有模型的Angular Material表动态列

74
我需要在没有模型的情况下使用angular material表格,因为我不知道服务中会返回什么。
所以我在组件中动态初始化我的MatTableDataSource和displayedColumns,就像这样:
TableComponent:
ngOnInit() {

this.vzfPuanTablo = [] //TABLE DATASOURCE

//GET SOMETHING FROM SERVICE 
this.listecidenKisi = this.listeciServis.listecidenKisi;
this.listecidenVazife = this.listeciServis.listecidenVazife;

//FILL TABLE DATASOURCE 
var obj = {};
for (let i in this.listecidenKisi ){
    for( let v of this.listecidenVazife[i].vazifeSonuclar){
        obj[v.name] = v.value;
    }
    this.vzfPuanTablo.push(obj);
    obj={};
}

//CREATE DISPLAYED COLUMNS DYNAMICALLY
this.displayedColumns = [];
for( let v in this.vzfPuanTablo[0]){
    this.displayedColumns.push(v);
}

//INITIALIZE MatTableDataSource
this.dataSource = new MatTableDataSource(this.vzfPuanTablo);
}

最重要的代码部分在这里:

for( let v in this.vzfPuanTablo[0]) {
   this.displayedColumns.push(v);
}
我在这里动态创建 displayedColumns,这意味着即使我不知道从服务中获取什么,我也可以在表格中显示它。
例如,displayedColumns 可以是这样的:
  • ["one", "two" , "three" , "four" , "five" ]
或者
  • ["stack","overflow","help","me]
但这不是问题,因为我可以处理它。

但是当我想在HTML中展示它时,由于matCellDef的原因,无法正确显示:

TableHtml:

    <mat-table #table [dataSource]="dataSource" class="mat-elevation-z8">

        <ng-container *ngFor="let disCol of displayedColumns; let colIndex = index" matColumnDef="{{disCol}}">
            <mat-header-cell *matHeaderCellDef>{{disCol}}</mat-header-cell>
            <mat-cell *matCellDef="let element "> {{element.disCol}}
            </mat-cell>
        </ng-container>

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

我的问题在这里:

<mat-cell *matCellDef="let element "> {{element.disCol}} < / mat-cell>
事实上,我想在单元格中显示element."disCol's value"的值,但我不知道如何做到这一点。
除此之外,一切都很好,只是这个element."disCol's value"的问题。
当我使用{{element.disCol}}来显示disCols的值为该元素的值时,所有单元格都是空的,如下所示:

enter image description here

另一个仅使用{{element}}的示例:

enter image description here


同时,正如您所见:

  1. 表格数据源正在动态更改。这意味着我无法轻松使用{{element.ColumnName}},因为我甚至不知道它是什么。

    • 第一个示例的displayedColumns=['Vazife'、'AdSoyad'、'Kirmizi'、'Mavi'、'Yesil'、'Sari'];
    • 第二个示例的displayedColumns=['Muhasebe'、'Ders'、'Egitim'、'Harici'];
  2. matHeaderCellDef是正确的,因为它直接使用了{{disCol}}。

但我需要读取disCol的值,并在单元格中显示element.(disCol的值)

我该怎么做?

4个回答

80

我找到了解决方案:) 它非常非常简单,但我一开始没看出来:) 只需要像这样:

        <mat-cell *matCellDef="let element "> {{element[disCol]}}
        </mat-cell>

我必须只在HTML中使用{{element[disCol]}}

现在,一切都没问题 :)


2
你能否请提供完整的示例代码,以便从API创建动态列并填充网格? - Techiemanu
感谢指出简洁明了的答案。我本来已经做好准备再次深入 “angularity” 的学习了。 :--) - Charlie Reitzel
1
@mevaka,能否提供创建动态列的完整代码?我在添加列时遇到了问题。我是基于按钮点击来添加列的。也就是说,如果有5个按钮,每次点击一个按钮,就会添加一列,并且行数也会增加。如果我添加了5列,就会出现5行,但我只需要一行。 - srikanth
只要您的对象数组键结构保持一致,您也可以使用类似以下代码动态生成列:this.displayedColumns = Object.keys(data[0]); - cody.codes
@mevaka 我的 displayedColumns 是一个对象数组(它有 id、label 等属性),所以 element[disCol] 对我无效,我尝试了 element[disCol.id]element.idelement.disCol.id,但都没有成功。你有什么想法吗? - Pinka
显示剩余2条评论

17

对于一个基于 @mevaka 的完整工作示例

其中 jobDetails$ 是项目数组。

columns$ 等同于 Object.keys(jobDetails$[0]),因此只是一个 string[]

<table mat-table [dataSource]="jobDetails$ | async">
  
  <ng-container *ngFor="let disCol of (columns$ | async); let colIndex = index" matColumnDef="{{disCol}}">
    <th mat-header-cell *matHeaderCellDef>{{disCol}}</th>
    <td mat-cell *matCellDef="let element">{{element[disCol]}}</td>
  </ng-container>


  <tr mat-header-row *matHeaderRowDef="(columns$ | async)"></tr>
  <tr mat-row *matRowDef="let row; columns: (columns$ | async)"></tr>
</table>

如果我们有一个动态表格,是否可以使用CSS应用不同的列大小?我想将我的静态表格转换为动态表格以支持两个不同的视图。 - Chandresh Mishra
@ChandreshMishra 我不知道为什么不行,试一试吧! - Jack
1
但是在哪里以及如何应用CSS类作为tr和td将由ngFor生成? - Chandresh Mishra
@CharlieReitzel,您能否详细说明一下?我有类似的需求。 - a p
看一下@rjsteinert的答案,它说明了我试图描述的内容。 - Charlie Reitzel
显示剩余2条评论

12
我已经尽力将一个动态表格简化到最小了。这个示例将显示给定平面对象数组中的任何列和任何键。请注意,第一个对象有一个额外的“foo”属性,导致创建整个列。DATA常量可以是从服务获取的数据。此外,如果您知道一些常见的属性名称,您可以将“列ID->标签”映射添加到其中,以便在获取JSON时使用。在这里查看stachblitz

import {Component, ViewChild, OnInit} from '@angular/core';

const DATA: any[] = [
  {position: 1, name: 'sdd', weight: 1.0079, symbol: 'H', foo: 'bar'},
  {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
  {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
  {position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
  {position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
  {position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'}
];

@Component({
  selector: 'dynamic-table-example',
  styleUrls: ['dynamic-table-example.css'],
  templateUrl: 'dynamic-table-example.html',
})
export class DynamicTableExample implements OnInit {

  columns:Array<any>
  displayedColumns:Array<any>
  dataSource:any
  
  ngOnInit() {
    // Get list of columns by gathering unique keys of objects found in DATA.
    const columns = DATA
      .reduce((columns, row) => {
        return [...columns, ...Object.keys(row)]
      }, [])
      .reduce((columns, column) => {
        return columns.includes(column)
          ? columns
          : [...columns, column]
      }, [])
    // Describe the columns for <mat-table>.
    this.columns = columns.map(column => {
      return { 
        columnDef: column,
        header: column,
        cell: (element: any) => `${element[column] ? element[column] : ``}`     
      }
    })
    this.displayedColumns = this.columns.map(c => c.columnDef);
    // Set the dataSource for <mat-table>.
    this.dataSource = DATA
  }
 
}
<mat-table #table [dataSource]="dataSource">
  <ng-container *ngFor="let column of columns" [cdkColumnDef]="column.columnDef">
    <mat-header-cell *cdkHeaderCellDef>{{ column.header }}</mat-header-cell>
    <mat-cell *cdkCellDef="let row">{{ column.cell(row) }}</mat-cell>
  </ng-container>
  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>


这个例子真的帮助我入门了,并且最接近文档。唯一的区别是现在推荐使用mat-table指令:<td mat-cell *cdkCellDef="let row">{{ column.cell(row) }}</td> - Chen Peleg
你如何添加其他单元格定义,例如按钮、复选框、下拉选择等? - Stephen Himes

0

从源(input type='checkbox')动态渲染数据表

我需要动态渲染列,并且期望将单元格的值呈现为复选框。我的代码是从Angular example table with filtering编辑而来,并从@Jack那里得到了动态渲染部分。希望下面附上的代码可以给像我这样的初学者提供一个简要的想法。

我所做的是

  1. <div *ngIf="condition"></div>包裹<td mat-cell... </td>
<div *ngIf="disCol === 'username'">
    <td mat-cell *matCellDef="let element"> {{element[disCol]}}</td>
</div>
<div *ngIf="disCol !== 'username'">
    <td mat-cell *matCellDef="let element">
        <input *ngIf="element[disCol] == 'Yes'" type="checkbox" />
        <input *ngIf="element[disCol] == 'No'" type="checkbox" checked/>
    </td>
</div>

值得一提的是,我使用的是 Angular 16 版本,导入语句与旧版本略有不同。旧版本基本上直接从 '@angular/material' 导入。
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatRippleModule } from '@angular/material/core';
import { MatTableModule } from '@angular/material/table';

dynamic-tb.component.html

<div class="example-container mat-elevation-z8">

  <mat-table #table [dataSource]="dataSource">
    <ng-container *ngFor="let disCol of displayedColumns; let colIndex = index" matColumnDef="{{disCol}}">
      <th mat-header-cell *matHeaderCellDef>{{disCol}}</th>
      <div *ngIf="disCol === 'username'">
        <td mat-cell *matCellDef="let element"> {{element[disCol] == undefined ? "-NA-" : element[disCol]}}</td>
      </div>
      <div *ngIf="disCol !== 'username'">
        <td mat-cell *matCellDef="let element">
          <input *ngIf="element[disCol] == 'Yes'" type="checkbox" />
          <input *ngIf="element[disCol] == 'No'" type="checkbox" checked/>
        </td>
      </div>
    </ng-container>"

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

dynamic-tb.component.ts

import { Component, OnInit } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';

@Component({
  selector: 'app-dynamic-tb',
  templateUrl: './dynamic-tb.component.html',
  styleUrls: ['./dynamic-tb.component.css']
})
export class DynamicTbComponent implements OnInit {

  displayedColumns: string[] = [];
  dataSource: any;
  ELEMENT_DATA: any[] | undefined;

  ngOnInit(): void {
    this.displayedColumns = ['username', 'feature_1', 'feature_2', 'feature_3'];
    this.ELEMENT_DATA = [
      { username: "Jonah", feature_1: 'Yes', feature_2: 'No', feature_3: 'No' },
      { username: "Alan", feature_1: 'Yes', feature_2: 'No', feature_3: 'Yes' },
      { username: "John", feature_1: 'No', feature_2: 'Yes', feature_3: 'No' },
      { username: "Ann", feature_1: 'Yes', feature_2: 'No', feature_3: 'Yes' },
      { username: "Lee", feature_1: 'No', feature_2: 'No', feature_3: 'No' },
      { username: "Royce", feature_1: 'Yes', feature_2: 'Yes', feature_3: 'No' },
      { username: "Suzzy", feature_1: 'No', feature_2: 'No', feature_3: 'No' },
    ];
    this.dataSource = new MatTableDataSource(this.ELEMENT_DATA);
  }

}

dynamic-tb.module.ts

import { NgModule } from '@angular/core';

import { DynamicTbComponent } from './profiles.component';
import { CommonModule } from '@angular/common';

import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatRippleModule } from '@angular/material/core';
import { MatTableModule } from '@angular/material/table';

@
NgModule
({
  declarations: [
    DynamicTbComponent
  ],
  imports: [
    CommonModule,
    MatButtonModule,
    MatFormFieldModule,
    MatInputModule,
    MatRippleModule,
    MatTableModule,
  ],
  exports: [
    DynamicTbComponent
  ]
})

export class DynamicTbModule {}

dynamic-tb.component.css

/* Structure */
.example-container {
  display: flex;
  flex-direction: column;
  min-width: 300px;
}

.example-header {
  min-height: 64px;
  padding: 8px 24px 0;
}

.mat-form-field {
  font-size: 14px;
  width: 100%;
}

.mat-table {
  overflow: auto;
  max-height: 500px;
}

/**
  Added by me
*/
th, td {
  width: 100px;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接