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

前端 未结 5 2558
孤城傲影
孤城傲影 2021-02-20 15:11

I am trying to pass multiple ng-template to my reusable component (my-table component), content projection. Now I need to get the reference value of ea

5条回答
  •  广开言路
    2021-02-20 15:55

    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. 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. I decided that any table level behavior (enable/disable pagination) would be controlled by @Input's in the table component. 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

    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).

    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:

    import { TemplateRef } from '@angular/core';
    
    export interface TableColumnConfig {
      displayName: string;
      key: string;
      customCellTemplate?: TemplateRef; // custom cell template!
    }
    

    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).

    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. 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;
      // 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

    Similar approach to what the OP showed in his answer. Since I added customCellTemplate as a property to TableColumnConfig, accessing it looks a bit cleaner. 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

    {{ col.displayName }}
    {{ row[col.key] }}

    Example: Consuming Component

    Sample use case where we want styled text in a column

    app-component.html

    For this bare minimum example, the table only has two inputs. I like to define the s for customCellTemplates at the bottom of the file instead of inside of the table tag itself for better readability imo.

    
    
    
    
    
    
      {{colorData}}
    
    

    app-component.ts

    export class AppComponent implements OnInit {
      @ViewChild("customCell", { static: true })
      customCell: TemplateRef;
      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.

提交回复
热议问题