【问题标题】:How to access child template in reusable component in Angular 8/9/10/11如何在 Angular 8/9/10/11 中访问可重用组件中的子模板
【发布时间】:2021-03-28 23:08:13
【问题描述】:

我已经创建了通用组件,它将以表格格式呈现数据。

data-table.component.ts(这是可复用的组件,任何子组件都可以使用)

    @Component({
      selector: 'data-table',
      templateUrl: './data-table.component.html',
      styleUrls: ['./data-table.component.css']
    })
    export class DataTableComponent implements OnInit {
    constructor() { }
    
      ngOnInit(): void {
         //wanted to access child here(or inside any method in this class) to set the width of each <td> from child
      //wanted to access #rowTemplate children from child for all 3 <td> 
      }
setColumnWidth(width: string = "") {
    if (width != "") {
      return 'width:' + width;
    }
  }
    }

data-table.component.html

<table style="width:100%;">
      <thead>
        <tr>
          <th *ngFor="let c of columns" style="{{setColumnWidth(c.width)}}">
            {{c.fieldTitle}}
          </th>
        </tr>
      </thead>
       <tbody>
        <ng-container *ngTemplateOutlet="rowTemplate"></ng-container>
      </tbody>
    </table>

resource-updates.component.ts(这是子组件)

    @Component({
      selector: 'resource-updates',
      templateUrl: './resource-updates.component.html',
      styleUrls: ['./resource-updates.component.css']
    })
    export class ResourceUpdatesComponent implements OnInit {
      columns: Column[] = [];
      rows: any[] = [];
     
      constructor() { }
    
      ngOnInit(): void {
        //Preparing list for columns
        this.columns.push(new Column({ fieldName: 'Id', fieldTitle: 'Id', isSortable: false, width: '5%' }));
        this.columns.push(new Column({ fieldName: 'Title', fieldTitle: 'Title', width: '60%' }));
        this.columns.push(new Column({ fieldName: 'Type', fieldTitle: 'Type', width: '35%' }));
      
       //Preparing list for rows
       this.rows = [
{"id":5,"title":"Air Gas Guideline","type":"PPT"},
{"id":6,"title":"Air Pollution User Reference","type":"Website"},
{"id":18,"title":"Avian Influenza (H7N9) User Reference","type":"Website"},
{"id":12,"title":"Avian Influenza (H7N9) for high risk","type":"PPT"},
{"id":11,"title":"Avian Influenza (H7N9) for normal","type":"PPT"}
];
      }
    }

resource-updates.component.html(想在下面的 Parent(公共组件)中从 columns.width 属性设置宽度)

  <ng-template #rowTemplate>
    <tr *ngFor="let r of rows">
      <td>{{r.id}}</td>
      <td>{{r.title}}</td>
      <td>{{r.type}}</td>
    </tr>
  </ng-template>
  <data-table [columns]="columns" [rowTemplate]="rowTemplate"></data-table>

任何机构都可以帮助访问 #rowTemplate 子元素以分别从 columns[0].width 和...

【问题讨论】:

    标签: angular datatable parent-child custom-component code-reuse


    【解决方案1】:

    您需要定义@ContentChild 并将@Input() 注释添加到您的DataTableComponent 中的列变量(包括您的问题中没有的Column 接口):

    export interface Column {
      fieldName: string;
      fieldTitle: string;
      isSortable?: boolean;
      width?: string;
    }
    
    @Component({
      selector: 'app-data-table',
      templateUrl: './data-table.component.html',
      styleUrls: ['./data-table.component.css']
    })
    export class DataTableComponent implements OnInit {
    
      @Input() columns: Column[] = [];
    
      @ContentChild('rowTemplate') rowTemplate: TemplateRef<any>;
    
      constructor() { }
    
      ngOnInit(): void {
      }
    }
    

    DataTableComponent 的模板应如下所示:

    <table style="width:100%;">
      <thead>
        <tr>
          <th *ngFor="let c of columns" [ngStyle]="{ width: c.width }">
            {{c.fieldTitle}}
          </th>
        </tr>
      </thead>
      <tbody>
        <ng-container *ngTemplateOutlet="rowTemplate"></ng-container>
      </tbody>
    </table>
    

    最后是ResourceUpdatesComponent 模板:

    <app-data-table [columns]="columns">
      <ng-template #rowTemplate>
        <tr *ngFor="let r of rows">
          <td>{{r.id}}</td>
          <td>{{r.title}}</td>
          <td>{{r.type}}</td>
        </tr>
      </ng-template>
    </app-data-table>
    

    Uploaded the working Angular project code to Github

    有一篇很好的文章解释了@ContentChild 的工作原理:Understanding ViewChildren, ContentChildren, and QueryList in Angular


    请注意,删除了 setColumnWidth() 函数并使用了 ngStyle,“每次运行 Angular 更改检测时都会调用它”,请参阅 Why you should never use function calls in Angular template expressions

    【讨论】:

      【解决方案2】:

      如果我没有理解错,你想从父组件访问子组件的 ng-template 吗?如果是,这就是我之前创建数据表控件时使用的情况。

      1. 您可以在其中创建一个带有 TemplateRef 的指令类:
      import { Directive, ContentChild, TemplateRef, Input } from "@angular/core";
      @Directive({ selector: "np-column" })
      export class NpColumnDirective {
            @Input() name: string;
            @ContentChild(TemplateRef) cellTemplate: TemplateRef<any>;
            constructor() { }
      }
      
      1. 然后在您的父组件中使用:

      @ContentChildren(NpColumnDirective) columnComponents: QueryList&lt;NpColumnDirective&gt;;

      这是我用于创建数据表的全部代码,仅供您参考: datatable demo

      【讨论】:

      • 谢谢您的回答,您的理解是正确的。让我验证一下您所说的内容以及如何实施。
      • 您能解释一下如何在子级和父级中访问 NpColumnDirective。非常感谢您的帮助......因为我是 Angular 的新手。我查看了您的代码,但由于知识有限,无法帮助我解决问题!
      • NpColumnDirective 为子角色,TableComponent 为父角色。这就是我们在 TableComponent 模板中访问 c​​hild 的地方, {{ row[column.headerName] }}
      • 感谢@Kevin Zhang 分享链接,但我仍然不明白如何使用它。我在您的代码中没有看到任何文档。如果您能提供更多信息,那就太好了。
      猜你喜欢
      • 2020-07-10
      • 1970-01-01
      • 2016-12-20
      • 2021-01-08
      • 2021-08-03
      • 2021-08-03
      • 2020-05-30
      • 2020-05-23
      • 1970-01-01
      相关资源
      最近更新 更多