【问题标题】:Content projection inside angular-material table角材料表内的内容投影
【发布时间】:2019-04-19 12:40:46
【问题描述】:

而不是向表格显示数据的常规方式。我正在尝试创建我的自定义表组件并通过 .

将数据投影到材料表中

像这样:

<table mat-table [dataSource]="dataSource">
	<!-- I want to Render the header and cell data here -->
	<ng-content></ng-content>
	
	<mat-header-row *matHeaderRowDef="headers; sticky: true"></mat-header-row>
	<mat-row *matRowDef="let row; columns: headers;"></mat-row>
</table>

所以我可以这样调用这个自定义组件:

<app-customized-table>
	<ng-container matColumnDef="id">
		<mat-header-cell *matHeaderCellDef> Id </mat-header-cell>
		<mat-cell *matCellDef="let element"> {{element.Id}} </mat-cell>
	</ng-container>
	...etc
</app-customized-table>

但是,它不会检测到内容。这是我正在尝试做的一个 stackblitz 示例。

https://stackblitz.com/edit/angular-qwvcln?file=src%2Fapp%2Fcustom-table.component.ts

有没有办法做到这一点?

谢谢。

【问题讨论】:

    标签: angular angular-material


    【解决方案1】:

    您必须采取非常不同的方法才能使其发挥作用。如您所见, mat-table 不能将其内容包装在其他内容中。一种可能性是仅将数据提供给您的自定义组件,而不是 DOM 作为内容。例如:

    组件:

    import { Component, OnInit, Input } from '@angular/core';
    
    @Component({
      selector: 'app-custom-table',
      template: `
        <div>
          {{name}}
    
          <div class="example-container mat-elevation-z8">
            <table mat-table [dataSource]="dataSource">
    
              <mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
              <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
    
              <ng-container *ngFor="let column of displayedColumns; index as i" >
    
                <ng-container [matColumnDef]="column">
                  <mat-header-cell *matHeaderCellDef>{{ columnLabels[i] }}</mat-header-cell>
                  <mat-cell mat-cell *matCellDef="let element"> {{element[valueKeys[i]]}} </mat-cell>
                </ng-container>
    
              </ng-container>
    
            </table>
          </div>
    
          asd
        </div>
      `
    })
    export class CustomTable implements OnInit {
      @Input() public columnLabels: any[];
      @Input() public displayedColumns;
      @Input() public dataSource;
      @Input() public name: any;
      @Input() public valueKeys: any[];
    
      constructor() { }
    
      ngOnInit() {
      }
    
    }
    

    用法:

    <app-custom-table name="sdf" 
        [dataSource]="dataSource" 
        [displayedColumns]="displayedColumns"
        [columnLabels]="columnLabels" 
        [valueKeys]="displayedColumns">
    
    </app-custom-table>
    

    地点:

    displayedColumns = ['position', 'name', 'weight', 'symbol'];
    dataSource = ELEMENT_DATA;
    columnLabels = ['No.', 'Name', 'Weight', 'Symbol'];
    

    但即便如此,也可能会面临更多挑战。

    【讨论】:

    • 谢谢。这是一个不错的选择。但是您是对的,挑战会随之而来,其中一个是很难自定义每个单元格的数据。嗯,这实际上是我的首要目标。
    • 结束了这个。当您想要包装表格并在表格之间有另一个组件以及将数据传递给它的组件时,唯一有效的解决方案。接受的 ng-content 解决方案在那时就失效了,因为 ContentChildren 无法再访问投影的 ng-content。
    【解决方案2】:

    聚会有点晚了,但我遇到了同样的挑战,并且能够通过以下方式解决它:

    您可以通过使用@ContentChildren@ViewChild 功能以编程方式将列定义添加到表中来解决此问题

    您的模板文件(例如customized-table.component.html):

    <table mat-table [dataSource]="dataSource">
        <ng-content></ng-content>
    
        <mat-header-row *matHeaderRowDef="headers; sticky: true"></mat-header-row>
        <mat-row *matRowDef="let row; columns: headers;"></mat-row>
    </table>
    

    你的代码隐藏(例如customized-table.component.ts):

    @Component({
        selector: 'app-customized-table',
        templateUrl: './customized-table.component.html'
    })
    export class CustomizedTableComponent<T> implements AfterContentInit {
        constructor() { }
    
        @Input() dataSource: T[]; // or whatever type of datasource you have
        @Input() headers: string[];
    
        // this is where the magic happens: 
        @ViewChild(MatTable, { static: true }) table: MatTable<T>;
        @ContentChildren(MatColumnDef) columnDefs: QueryList<MatColumnDef>;
    
        // after the <ng-content> has been initialized, the column definitions are available.
        // All that's left is to add them to the table ourselves:
        ngAfterContentInit() {
            this.columnDefs.forEach(columnDef => this.table.addColumnDef(columnDef));
        }
    }
    
    

    现在,您可以使用:

    <app-customized-table [headers]="headers">
        <ng-container matColumnDef="id">
            <mat-header-cell *matHeaderCellDef> Id </mat-header-cell>
            <mat-cell *matCellDef="let element"> {{element.Id}} </mat-cell>
        </ng-container>
        ...etc
    </app-customized-table>
    

    Stackblitz working demo with lazy loaded modules

    【讨论】:

    • 我试过这个,但它不起作用,你是如何让它工作的?我的情况是延迟加载模块内的表加载,错误给我它是找不到 id 列..真的需要解决这个问题否则代码必须重复编写,这是不可维护的,因为我的应用程序需要大量表。
    • 您是否将CustomizedTableComponent 放入shared module 并将该模块导入您的延迟加载模块中?
    • @Stefan 添加了一个 stackblitz 示例。您将columnDefs 用于displayedColumns 的解决方案取消了选择要显示的列以及独立于列定义的顺序的选项。确保将 MatTableModule 以某种方式导入到您使用自定义表格组件的模块中(参见 stackblitz 示例)
    • 当然可以!只需在添加表格的组件中添加@ViewChild(MatSort, { static: true }) sort: MatSort;(所以不是自定义表格组件),并确保在您想要的标题单元格上具有mat-sort-header属性能够排序。然后使用this.sort 来实现你的排序逻辑。
    • @LetieTechera 你的表是否在条件容器中(例如使用*ngIf)?如果是这样,请使用static: false。更好的是,下载 stackblitz 项目并从那里开始工作。
    【解决方案3】:

    您可以像这样投影内容:

    <ng-container *ngFor=”let column of displayedColumns” matColumnDef=”{{column.id}}”>
       <th mat-header-cell *matHeaderCellDef mat-sort-header>{{column.name}}</th>
       <td mat-cell *matCellDef=”let row”>
          {{row[column.id]}}
       </td>
    </ng-container>
    

    然后你传递内容投影的模板:

    <my-component …
    [itemTemplate]=”itemTemplate”>
       <ng-template let-item #itemTemplate>
          column id: {{item.column.id}}
          value: {{item.value}}
       </ng-template>
    </my-component>
    

    source

    【讨论】:

      猜你喜欢
      • 2018-06-22
      • 2020-07-04
      • 1970-01-01
      • 1970-01-01
      • 2017-11-16
      • 2018-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多