简体   繁体   English

使用 angular 5 中的 contentChildren 获取多个 ng-template ref 值

[英]Get multiple ng-template ref values using contentChildren in angular 5

I am trying to pass multiple ng-template to my reusable component (my-table component), content projection.我正在尝试将多个ng-template传递给我的可重用component (my-table 组件),内容投影。 Now I need to get the reference value of each passed ng-template so I can use that value to know, which template is passed for which column.现在我需要获取每个传递的ng-template的参考值,以便我可以使用该值来知道为哪一列传递了哪个模板。 Basically I am creating a reusable table component (on top of Angular material table) where user can pass an separate template for each column.基本上,我正在创建一个可重用的表组件(在 Angular 材料表之上),用户可以在其中为每列传递一个单独的模板。

Kindly suggest - OR is there a better approach of doing this?请建议 - 或者有没有更好的方法来做到这一点?

temp.component.ts temp.component.ts

import { Component, OnInit, ContentChildren, QueryList, TemplateRef, AfterContentInit } from '@angular/core';

@Component({
  selector: 'my-table',
  template: `<h1>This is the temp component</h1>`,
  styleUrls: ['./temp.component.scss']
})
export class TempComponent implements OnInit, AfterContentInit {

  constructor() { }

  @ContentChildren(TemplateRef) tempList: QueryList<TemplateRef<any>>;

  ngOnInit() {
  }

  ngAfterContentInit() {
      console.log('template list');
      console.log(this.tempList);
  }
}

app.component.html应用程序组件.html

<my-table>
    <ng-template #column1 let-company let-func="func">
        <h1>this template is for column 1</h1>
    </ng-template>
    <ng-template #column2 let-company let-func="func">
        <h1>this template is for column 2</h1>
    </ng-template>
</my-table>

I can create directive for each column, but than no of column might change so directive route will not work.我可以为每一列创建指令,但没有列可能会改变,因此指令路由将不起作用。 I am thinking that, component user will pass each column template with template ref value as column header value, for example, if user is passing an ng-template for "firstName" column, it should be like ,我在想,组件用户将使用模板引用值作为列标题值传递每个列模板,例如,如果用户为“firstName”列传递一个ng-template ,它应该像,

 <ng-template #firstName let-firstname>
     <h1>this template is for column firstName</h1>
 </ng-template> 

And I need a way to get all the provided ng-template with their ref so I can know, which template belongs to which column.而且我需要一种方法来获取所有提供的ng-template及其引用,以便我知道哪个模板属于哪个列。

A Directive is a good approach for this so you are already thinking in the right direction. Directive是一种很好的方法,因此您已经在朝着正确的方向思考。 Directives support also input parameters so you can specify the column name or header as the parameter to the directive.指令还支持输入参数,因此您可以指定列名称或标题作为指令的参数。 Check also the official documentation for more details.另请查看官方文档以获取更多详细信息。

Here is a sample directive using this approach:这是使用此方法的示例指令:

import { Directive, TemplateRef, Input } from '@angular/core';

@Directive({
  selector: '[tableColumn]'
})
export class TableColumnDirective {

  constructor(public readonly template: TemplateRef<any>) { }

  @Input('tableColumn') columnName: string;
}

As you can see the directive has an input property that will receive the column name and also it injects the TemplateRef so you can access it directly from the directive.如您所见,该指令有一个输入属性,该属性将接收列名,并且它还注入TemplateRef以便您可以直接从指令访问它。

You can then define the columns like this:然后,您可以像这样定义列:

<ng-template tableColumn="firstname" let-firstname>
   <h1>this template is for column firstName</h1>
</ng-template>
<ng-template tableColumn="lastName" let-lastname>
   <h1>this template is for column lastName</h1>
</ng-template>

In the component you then query the ContentChildren by the directive and get all the directives which gives you access to the column names and templates.在组件中,您然后通过指令查询ContentChildren并获取所有允许您访问列名称和模板的指令。

Here is the updated component:这是更新的组件:

import { Component, OnInit, ContentChildren, QueryList, TemplateRef, AfterContentInit } from '@angular/core';


@Component({
  selector: 'my-table',
  template: `<h1>This is the temp component</h1>`,
  styleUrls: ['./temp.component.scss']
})
export class TempComponent implements OnInit,AfterContentInit {

  constructor() { }
  @ContentChildren(TableColumnDirective) columnList: QueryList<TableColumnDirective>;
  ngOnInit() {
  }

  ngAfterContentInit(){
    console.log('column template list');
    console.log(this.columnList.toArray());
  }

}

Here is a slightly different way to do it maybe you like this more.这是一种稍微不同的方法,也许你更喜欢这个。 I will now base it on your custom table sample since you provided more information.由于您提供了更多信息,我现在将基于您的自定义表格示例。

You can create a directive that takes content and you specify the template as the content.您可以创建一个接受内容的指令,并将模板指定为内容。 Here is a sample implementation:这是一个示例实现:

@Directive({
  selector: 'custom-mat-column',
})
export class CustomMatColumnComponent {
  @Input() public columnName: string;
  @ContentChild(TemplateRef) public columnTemplate: TemplateRef<any>;
}

Then your parent component template will change to this:然后你的父组件模板会变成这样:

<custom-mat-table [tableColumns]="columnList" [tableDataList]="tableDataList 
   (cellClicked)="selectTableData($event)" (onSort)="onTableSort($event)" class="css-class-admin-users-table">
  <custom-mat-column columnName="firstname">
    <ng-template let-item let-func="func">
      <div class="css-class-table-apps-name">
        <comp-avatar [image]="" [name]="item?.processedName" [size]="'small'"></comp-avatar>
        <comp-button (onClick)="func(item)" type="text">{{item?.processedName}}</comp-button>
      </div>
    </ng-template>
  </custom-mat-column>
  <custom-mat-column columnName="status">
    <ng-template #status let-item>
      <div [ngClass]="{'item-active' : item?.status, 'item-inactive' : !item?.status}"
        class="css-class-table-apps-name">{{item?.status | TextCaseConverter}}
      </div>
    </ng-template>
  </custom-mat-column>
  <custom-mat-column columnName="lastname">
    <ng-template #lastname let-item>
      <div class="css-class-table-apps-name">
        {{item?.lastname}}</div>
    </ng-template>
  </custom-mat-column>
</custom-mat-table>

Your custom table component needs to be changed.您的自定义表格组件需要更改。 instead of receiving the templateNameList it needs to generate it from the ContentChildren on demand.它需要根据需要从ContentChildren生成它,而不是接收templateNameList

@Component({
    selector: 'custom-mat-table',
    templateUrl: './customTable.component.html',
    styleUrls: ['./customTable.component.scss']
})
export class NgMatTableComponent<T> implements OnChanges, AfterViewInit {
  @ContentChildren(CustomMatColumnComponent) columnDefinitions: QueryList<CustomMatColumnComponent>;
  templateNameList: { [key: string]: TemplateRef<any> } {
    if (this.columnDefinitions != null) {
      const columnTemplates: { [key: string]: TemplateRef<any> } = {};
      for (const columnDefinition of this.columnDefinitions.toArray()) {
        columnTemplates[columnDefinition.columnName] = columnDefinition.columnTemplate;
      }
      return columnTemplates;
    } else {
      return {};
    }
  };
  @Input() tableColumns: TableColumns[] = [];
  @Input() tableDataList: T[] = [];
  @Output() cellClicked: EventEmitter<PayloadType> = new EventEmitter();
  @Output() onSort: EventEmitter<TableSortEventData> = new EventEmitter();
  displayedColumns: string[] = [];
  tableDataSource: TableDataSource<T>;
  @ViewChild(MatSort) sort: MatSort;

  constructor() {
      this.tableDataSource = new TableDataSource<T>();
  }

  onCellClick(e: T, options?: any) {
      this.cellClicked.emit({ 'row': e, 'options': options });
  }

  ngOnChanges(change: SimpleChanges) {
      if (change['tableDataList']) {
          this.tableDataSource.emitTableData(this.tableDataList);
          this.displayedColumns = this.tableColumns.map(x => x.displayCol);
      }

  }

  ngAfterViewInit() {
      this.tableDataSource.sort = this.sort;
  }

  sortTable(e: any) {
      const { active: sortColumn, direction: sortOrder } = e;
      this.onSort.emit({ sortColumn, sortOrder });
  }
}

If you don't like this second approach you can still use what I suggested in the original sample in the same way.如果您不喜欢第二种方法,您仍然可以以相同的方式使用我在原始示例中建议的内容。 The only difference is how it looks in the template.唯一的区别是它在模板中的外观。 I created also a StackBlitz sample so you can see it in practice.我还创建了一个StackBlitz 示例,以便您可以在实践中看到它。

There is another approach for creating the custom table component.还有另一种创建自定义表格组件的方法。 Instead of exposing just the columns, you can have the access to the entire rows.您可以访问整行,而不是只公开列。 So you can have the direct control over the entire columns.因此,您可以直接控制整个列。

custom-table.component.html custom-table.component.html

<table>

    <!-- Caption -->
    <ng-container *ngTemplateOutlet="captionTemplate ? captionTemplate: defaultCaption; context:{$implicit: caption}">
    </ng-container>

    <!-- Header -->
    <thead>
        <ng-container *ngTemplateOutlet="headerTemplate ? headerTemplate: defaultHeader; context:{$implicit: columns}">
        </ng-container>
    </thead>

    <!-- Body -->
    <tbody>
        <!-- Here we will provide custom row Template -->
        <ng-template ngFor let-rowData let-rowIndex="index" [ngForOf]="values">
            <ng-container
                *ngTemplateOutlet="bodyTemplate ? bodyTemplate: defaultBody; context:{$implicit: rowData,columns: columns , index:rowIndex }">
            </ng-container>
        </ng-template>
    </tbody>

    <!-- Footer -->
    <tfoot>
        <ng-template ngFor let-rowData let-rowIndex="index" [ngForOf]="footerValues">
            <ng-container
                *ngTemplateOutlet="footerTemplate ? footerTemplate: defaultFooter; context:{$implicit: rowData,columns: columns , index:rowIndex }">
            </ng-container>
        </ng-template>
    </tfoot>

</table>

<!-- Caption Default Template -->
<ng-template #defaultCaptio let-caption>
    <caption *ngIf="caption">{{caption}}</caption>
</ng-template>

<!-- Header Default Template -->
<ng-template #defaultHeader let-columns>
    <tr>
        <th *ngFor="let column of columns">{{column.title}}</th>
    </tr>
</ng-template>

<!-- Body Default Template -->
<ng-template #defaultBody let-item let-columns="columns">
    <tr>
        <td *ngFor="let column of columns">{{item[column.key]}}</td>
    </tr>
</ng-template>

<!-- Footer Default Template -->
<ng-template #defaultFooter>
    <tr *ngFor="let item of footerValues">
        <td *ngFor="let column of columns">{{item[column.key]}}</td>
    </tr>
</ng-template>

custom-table.component.ts custom-table.component.ts

import {
  Component,
  OnInit,
  Input,
  TemplateRef,
  ContentChild
} from "@angular/core";

@Component({
  selector: "app-custom-table",
  templateUrl: "./custom-table.component.html",
  styleUrls: ["./custom-table.component.css"]
})
export class CustomTableComponent implements OnInit {
  @Input()
  caption: string;

  @Input()
  columns: { title: string; key: string }[] = [];

  @Input()
  values: any[] = [];

  @Input()
  footerValues: any[] = [];

  @ContentChild("caption", { static: false })
  captionTemplate: TemplateRef<any>;

  @ContentChild("header", { static: false })
  headerTemplate: TemplateRef<any>;

  @ContentChild("body", { static: false })
  bodyTemplate: TemplateRef<any>;

  @ContentChild("footer", { static: false })
  footerTemplate: TemplateRef<any>;

  constructor() {}

  ngOnInit() {}
}

Now you can provide the details as follows,现在您可以提供以下详细信息,

<app-custom-table [columns]="columns" [values]="values" [footerValues]="footerValues">

    <!-- Caption Custom Template -->
    <ng-template #caption>
        <caption>Custom Table</caption>
    </ng-template>

    <!-- Header Custom Template -->
    <ng-template #header let-columns>
        <tr>
            <th *ngFor="let column of columns">[{{column.title}}]</th>
        </tr>
    </ng-template>

    <!-- Body Custom Template -->
    <ng-template #body let-item let-columns="columns">
        <tr *ngIf="item.id === 1 else diff">
            <td *ngFor="let column of columns">
                <span *ngIf="column.title === 'Name'" style="background-color: green">{{item[column.key]}}</span>
                <span *ngIf="column.title !== 'Name'">{{item[column.key]}}</span>
            </td>
        </tr>
        <ng-template #diff>
            <tr style="background-color: red">
                <td *ngFor="let column of columns">{{item[column.key]}}</td>
            </tr>
        </ng-template>
    </ng-template>

    <!-- Footer Custom Template -->
    <ng-template #footer let-item let-columns="columns">
        <tr>
            <td [colSpan]="columns.length">{{item.copyrightDetails}}</td>
        </tr>
    </ng-template>
</app-custom-table>

I have created a stackblitz for the same.我为此创建了一个stackblitz。 Please refer this .请参考这个

I've had to build lots of table components that used Angular Material's MatTable , and at some point I decided to save myself some time in the long run by building a base table that is dynamic and reusable.我不得不构建许多使用 Angular Material 的MatTable的表格组件,从长远来看,我决定通过构建一个动态且可重用的基表来节省一些时间。 I've added a bit more context / thought process around how to get up and running with a bare minimum dynamic reusable table, before talking about how to add a specific feature to it.在讨论如何向其添加特定功能之前,我已经添加了更多关于如何使用最少的动态可重用表启动和运行的上下文/思考过程。

Advice for Building a Dynamic and Reusable Table构建动态和可重用表的建议

The first thing I did (after adding Angular Material to the project) was determine how I want consumers to use my table.我做的第一件事(在向项目添加 Angular Material 之后)是确定我希望消费者如何使用我的表。 I decided that any table level behavior (enable/disable pagination) would be controlled by @Input 's in the table component.我决定任何表级行为(启用/禁用分页)都将由表组件中的@Input控制。 However as I developed it further, I realized most of the new functionality I needed should really be controlled per-column.然而,当我进一步开发它时,我意识到我需要的大部分新功能实际上应该按列进行控制。 The rest of this answer is focused on the per-column configuration.此答案的其余部分侧重于每列配置。

TableColumnConfig Interface - adding a new feature TableColumnConfig接口 - 添加新功能

I started off by defining an interface for a configuration object (just like OP did with TableColumns except mine is called TableColumnConfig . The bare minimum needed for dynamic and reusable functionality are two strings that you use to access the data in each row and to display the column name (I use key and displayName ).我首先为配置对象定义了一个接口(就像 OP 对TableColumns所做的那样,除了我的称为TableColumnConfig 。动态和可重用功能所需的最低限度是两个字符串,您可以使用它们来访问每一行中的数据并显示列名(我使用keydisplayName )。

If we want to add the ability for consumers of the component to pass in a custom cell template, I'd first add a property to the TableColumnConfig interface like so:如果我们想为组件的使用者添加传递自定义单元格模板的能力,我首先要向TableColumnConfig接口添加一个属性,如下所示:

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

export interface TableColumnConfig {
  displayName: string;
  key: string;
  customCellTemplate?: TemplateRef<any>; // custom cell template!
}

my-table-component.ts my-table-component.ts

I believe I started with the Angular Material schematic for generating a table component, but I didn't like the amount of boilerplate for something bare minimum like this example (it's easy enough to add pagination and sorting later).我相信我是从用于生成表格组件的 Angular Material 原理图开始的,但我不喜欢像这个示例这样的最少样板的数量(稍后添加分页和排序很容易)。

You don't need to do anything special in the table-component.ts for custom the custom cell template functionality (just note we are expecting TableColumnConfig[] from the consuming component), but showing the code below for completeness.您不需要在 table-component.ts 中做任何特殊的事情来自定义自定义单元格模板功能(请注意,我们期待来自消费组件的TableColumnConfig[] ),但为了完整TableColumnConfig[] ,请显示下面的代码。 Most of the times when I needed to add a per-column feature, I never even had to mess with this file.大多数时候,当我需要添加每列功能时,我什至不必弄乱这个文件。

import { Component, OnInit, Input } from '@angular/core';
import { MatTableDataSource } from '@angular/material';
import { TableColumnConfig } from './table-column-config';

@Component({
  selector: 'app-my-table',
  templateUrl: './my-table.component.html',
  styleUrls: ['./my-table.component.css']
})
export class MyTableComponent implements OnInit {
  @Input() data: any[];
  @Input() columnConfigs: TableColumnConfig[];
  dataSource: MatTableDataSource<any>;
  // need a string array for *matHeaderRowDef and *matRowDef
  displayedColumns: string[];

  ngOnInit() {
    this.displayedColumns = this.columnConfigs.map(config => config.key);
    this.dataSource = new MatTableDataSource(this.data);
  }
}

my-table-component.html我的表组件.html

Similar approach to what the OP showed in his answer.类似于 OP 在他的回答中显示的方法。 Since I added customCellTemplate as a property to TableColumnConfig , accessing it looks a bit cleaner.由于我将customCellTemplate作为属性添加到TableColumnConfig ,因此访问它看起来更customCellTemplate Also just a note that for this demo I decided to only expose column data to customCellTemplates, but you could easily return the entire row if necessary by changing $implicit: row[col.key] to $implicit: row还要注意的是,对于这个演示,我决定只将列数据公开给 customCellTemplates,但如果需要,您可以通过将$implicit: row[col.key]更改$implicit: row[col.key]轻松返回整$implicit: row

<div class="mat-elevation-z8">
  <mat-table class="full-width-table" [dataSource]="dataSource">
    <!-- NgFor Columns -->
    <ng-container *ngFor="let col of columnConfigs" matColumnDef="{{ col.key }}">
      <mat-header-cell *matHeaderCellDef> {{ col.displayName }}
      </mat-header-cell>

      <mat-cell *matCellDef="let row">
        <!-- handle custom cell templates -->
        <div *ngIf="!col.customCellTemplate; else customCellTemplate">
            {{ row[col.key] }}
        </div>
        <ng-template #customCellTemplate>
          <!-- for now, only exposing row[col.key] instead of entire row -->
          <ng-template [ngTemplateOutlet]="col.customCellTemplate"
            [ngTemplateOutletContext]="{ $implicit: row[col.key] }">
          </ng-template>
        </ng-template>
      </mat-cell>
    </ng-container>

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

Example: Consuming Component示例:消费组件

Sample use case where we want styled text in a column我们希望在列中设置样式文本的示例用例

app-component.html应用组件.html

For this bare minimum example, the table only has two inputs.对于这个最低限度的示例,该表只有两个输入。 I like to define the <ng-template> s for customCellTemplates at the bottom of the file instead of inside of the table tag itself for better readability imo.我喜欢在文件底部而不是在 table 标签本身内部为 customCellTemplates 定义<ng-template> s,以获得更好的可读性imo。

<app-my-table [data]="tableData" [columnConfigs]="columnConfigs">
</app-my-table>

<!-- Custom cell template for color column -->
<!-- name the $implicit variable 'let-whateverIwant' -->
<ng-template #customCell let-colorData>
  <span [ngStyle]="{'color': colorData}">{{colorData}}</span>
</ng-template>

app-component.ts app-component.ts

export class AppComponent implements OnInit {
  @ViewChild("customCell", { static: true })
  customCell: TemplateRef<any>;
  columnConfigs: TableColumnConfig[];

  tableData = [
    { id: 1, name: "Chris", color: "#FF9900" },
    { id: 2, name: "Akash", color: "blue" }
  ];

  // we can't reference our {static:true} TemplateRef until ngOnInit
  ngOnInit() {
    this.columnConfigs = [
      { key: "id", displayName: "ID" },
      { key: "name", displayName: "Name" },
      {
        key: "color",
        displayName: "Favorite Color",
        customCellTemplate: this.customCell
      }
    ];
  }
}

Check out my StackBlitz demo for a few more code comments.查看我的StackBlitz 演示以获取更多代码注释。

I have built a table component in my library Easy Angular https://github.com/adriandavidbrand/ngx-ez/tree/master/projects/ngx-ez/src/lib/ez-table我在我的库 Easy Angular https://github.com/adriandavidbrand/ngx-ez/tree/master/projects/ngx-ez/src/lib/ez-table 中构建了一个表组件

Each column can take a template via a ViewChild每列都可以通过 ViewChild 获取一个模板

@ContentChild(TemplateRef)
template: TemplateRef<any>;

The table uses ContentChildren to get the columns该表使用 ContentChildren 来获取列

@ContentChildren(EzColumnComponent)
columns: QueryList<EzColumnComponent>;

and the table component passes the current item in with a context when rendering并且表格组件在渲染时将当前项目与上下文一起传递

<ng-container *ngTemplateOutlet="column.template || defaultColumTemplate;context:{ $implicit: item, index: i }"></ng-container>

and is used like并且像这样使用

<ez-table [data]="data">
  <ez-column heading="Heading" property="prop">
    <ng-template let-item>
      Use item view variable in template here
    </ng-template>
  </ez-column>
<ez-table>

Here is a demo of how it works这是它如何工作的演示

https://stackblitz.com/edit/angular-npn1p1 https://stackblitz.com/edit/angular-npn1p1

There is quite a bit to this table but all the source is up on GitHub.这张表有很多内容,但所有源代码都在 GitHub 上。

I have created the below custom table component, on top of angular material table component.我在角材料表组件之上创建了以下自定义表组件。

Following were my business requirement,以下是我的业务需求,

  1. every cell can have multiple component OR plain text OR image.每个单元格都可以有多个组件或纯文本或图像。
  2. table should be sortable表应该是可排序的
  3. column might not have header values(empty header) but can have cell content.列可能没有标题值(空标题)但可以有单元格内容。

So I need to have the full control on each cell template and the events raised by any element from within the cell.所以我需要完全控制每个单元格模板以及单元格内任何元素引发的事件。

customTable.component.html customTable.component.html

<div class="mat-elevation-z8 css-class-table">
  <mat-table #table [dataSource]="tableDataSource" matSort (matSortChange)="sortTable($event)">
    <ng-container *ngFor="let col of tableColumns; let colIndex=index" matColumnDef="{{col?.displayCol}}">
      <mat-header-cell *matHeaderCellDef mat-sort-header class="css-class-table-header css-class-table-header-visibility">
        {{col?.headerCol}}
      </mat-header-cell>
      <mat-cell *matCellDef="let row; let i=index" >
        <ng-container [ngTemplateOutlet]="templateNameList[col?.displayCol] || noTemplate"
          [ngTemplateOutletContext]="{$implicit:row,func:onCellClick.bind(this)}">
        </ng-container>
        <ng-template #noTemplate>
          {{row[col.displayCol]}}
        </ng-template>

      </mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns; let i=index"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns; let i=index" class="css-class-grid-row"></mat-row>

  </mat-table>

</div>

customTable.component.ts customTable.component.ts

import { Component, Input, ViewChild, AfterViewInit, OnChanges, Output, EventEmitter, TemplateRef, SimpleChanges, ContentChild, ContentChildren } from '@angular/core';
import { MatTableDataSource, MatSort, MatPaginator } from '@angular/material';
import { DataSource } from '@angular/cdk/table';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';

export interface TableColumns {
    displayCol: string;
    headerCol: string;
}

export interface TableSortEventData {
    sortColumn: string;
    sortOrder: string;
}

export interface PayloadType {
    row: any;
    options?: any;
}


@Component({
    selector: 'custom-mat-table',
    templateUrl: './customTable.component.html',
    styleUrls: ['./customTable.component.scss']
})
export class NgMatTableComponent<T> implements OnChanges, AfterViewInit {
    @Input() templateNameList: Object;
    @Input() tableColumns: TableColumns[] = [];
    @Input() tableDataList: T[] = [];
    @Output() cellClicked: EventEmitter<PayloadType> = new EventEmitter();
    @Output() onSort: EventEmitter<TableSortEventData> = new EventEmitter();
    displayedColumns: string[] = [];
    tableDataSource: TableDataSource<T>;
    @ViewChild(MatSort) sort: MatSort;

    constructor() {
        this.tableDataSource = new TableDataSource<T>();
    }

    onCellClick(e: T, options?: any) {
        this.cellClicked.emit({ 'row': e, 'options': options });
    }

    ngOnChanges(change: SimpleChanges) {
        if (change['tableDataList']) {
            this.tableDataSource.emitTableData(this.tableDataList);
            this.displayedColumns = this.tableColumns.map(x => x.displayCol);
        }

    }

    ngAfterViewInit() {
        this.tableDataSource.sort = this.sort;
    }

    sortTable(e: any) {
        const { active: sortColumn, direction: sortOrder } = e;
        this.onSort.emit({ sortColumn, sortOrder });
    }

}

export class TableDataSource<T> extends DataSource<T> {

    tableDataSubject = new BehaviorSubject<T[]>([]);
    sort: MatSort | null;
    private _sort;

    constructor() {
        super();
    }

    emitTableData(data: T[]) {
        this.tableDataSubject.next(data);
    }

    connect(): Observable<T[]> {
        return this.tableDataSubject.asObservable();
    }

    disconnect() {
        this.tableDataSubject.complete();
    }
}

in the parent.component.html在 parent.component.html 中

<custom-mat-table [tableColumns]="columnList" [tableDataList]="tableDataList"
[templateNameList]="{'firstname':firstname,'lastname':lastname,'status':status}"
(cellClicked)="selectTableData($event)" (onSort)="onTableSort($event)" class="css-class-admin-users-table">
<ng-template #firstname let-item let-func="func">
    <div class="css-class-table-apps-name">
        <comp-avatar [image]="" [name]="item?.processedName" [size]="'small'"></comp-avatar>
        <comp-button (onClick)="func(item)" type="text">{{item?.processedName}}</comp-button>
    </div>
</ng-template>
<ng-template #status let-item>
    <div [ngClass]="{'item-active' : item?.status, 'item-inactive' : !item?.status}"
        class="css-class-table-apps-name">{{item?.status | TextCaseConverter}}
</div>
</ng-template>
<ng-template #lastname let-item>
    <div class="css-class-table-apps-name">
        {{item?.lastname}}</div>
</ng-template>
</custom-mat-table>

parent.component.ts父组件.ts

columnList: TableColumns[] = [
    { displayCol: 'firstname', headerCol: 'First Name' },
    { displayCol: 'lastname', headerCol: 'Last Name' },
    { displayCol: 'status', headerCol: 'Status' }
];

templateList: Object = "{'firstname':firstname,'lastname':lastname,'status':status}";

onTableSort(e: TableSortEventData) {
    this.sortQueryParam = {};
    if (e && e.sortOrder !== '') {
        this.sortQueryParam['sortBy'] = e.sortColumn;
        this.sortQueryParam['order'] = e.sortOrder.toUpperCase();
    }
    else {
        this.sortQueryParam = null;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM