如何在Angular 8/9/10/11中的可重用组件中访问子模板

3
我已经创建了通用组件,可将数据以表格形式呈现。 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(想要从columns.width属性中在父组件(通用组件)下设置下面3个的宽度)

  <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设置宽度,依此类推...

2个回答

3

您需要定义 @ContentChild 并在您的 DataTableComponent 中的 columns 变量上添加 @Input() 注释(包括您问题中没有的 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>

已将可工作的Angular项目代码上传至Github

有一篇很好的文章解释了@ContentChild的工作原理:Angular中理解ViewChildren、ContentChildren和QueryList


请注意,已删除setColumnWidth()函数并使用了ngStyle,“这将在每次Angular变更检测运行时调用”,请参见为什么不应在Angular模板表达式中使用函数调用


1
如果我没有理解错的话,您想从父组件访问子组件的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<NpColumnDirective>;

这是我创建数据表所使用的完整代码,仅供参考: datatable demo


感谢您的回答,您的理解是正确的。让我确认一下您所说的内容以及如何实施。 - imdadhusen
你能解释一下如何在子组件和父组件中访问NpColumnDirective吗?非常感谢您的帮助,因为我是Angular的新手。我查看了您的代码,但由于我的知识有限,无法帮助我解决问题! - imdadhusen
NpColumnDirective 扮演子角色,而 TableComponent 扮演父角色。这是我们在 TableComponent 模板中访问子级的位置, <span *ngIf="!column.isCheckbox" [style.flex]="'0 1 ' + column.width"> <ng-container *ngIf="!column.template">{{ row[column.headerName] }}</ng-container> <ng-container *ngIf="column.template"> <ng-container *ngTemplateOutlet="column.template; context: { row: row }"> </ng-container> </ng-container> </span> - Kevin Zhang
这是一个使用数据表的示例,https://github.com/KevinZhang19870314/pluto-ui/blob/master/src/app/sample/table/table.component.html - Kevin Zhang
谢谢 @Kevin Zhang 分享链接,但是我仍然不知道如何使用它。你的代码中没有任何文档说明。如果你能提供更多信息就太好了。 - imdadhusen
显示剩余2条评论

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