如何从列表显示ng-templates

bal*_*man 6 ng-template angular

我有一个AppComponent包含的列表ShapeComponents。我实现了一些部件延伸的ShapeComponent喜欢LineComponentCircleComponentRectangleComponent。他们每个人都有自己ng-template#shapeTemplate。在我的app.component.html我要遍历列表ShapeComponents并显示每个ng-template(从LineComponentCircleComponent等等)。

所以我有

shapes: ShapeComponent[] = []
Run Code Online (Sandbox Code Playgroud)

其中包含LineComponent,CircleComponent等

我想要这样的事情

<div *ngFor="let shape of shapes">
    <!-- How to display the ng-template from for example LineComponent or Circle -->
</div>
Run Code Online (Sandbox Code Playgroud)

我认为使用@ViewChildren或@ContentChildren会很有用,但不知道如何处理

Bun*_*ner 5

我最近也做过类似的事情。这是最后的stackblitz

首先,我创建一个 ShapeComponent

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

@Component({
  selector: 'shape',
  template: `<ng-template><ng-content></ng-content></ng-template>`,
})
export class ShapeComponent  {

  @ViewChild(TemplateRef) template: TemplateRef<any>;
}
Run Code Online (Sandbox Code Playgroud)

它的模板有一个 ,ng-template以便我们可以引用它,ng-content因此该组件的使用者可以将他们的内容投影到其中。

通过 ,@ViewChild(TemplateRef)您可以获得 的参考ng-template以及其中的任何内容ng-content

让我们创建一个LineComponent

@Component({
  selector: 'line',
  template: `<ng-template>
    This is line and its content: <ng-content></ng-content>
  </ng-template>`,
  providers: [{
    provide: ShapeComponent,
    useExisting: forwardRef(() => LineComponent)
  }]
})
export class LineComponent extends ShapeComponent  {}
Run Code Online (Sandbox Code Playgroud)

CircleComponent

@Component({
  selector: 'circle',
  template: `<ng-template>
    This is circle and its content: <ng-content></ng-content>
  </ng-template>`,
  providers: [{
    provide: ShapeComponent,
    useExisting: forwardRef(() => CircleComponent)
  }]
})
export class CircleComponent extends ShapeComponent  {}
Run Code Online (Sandbox Code Playgroud)

ShapeComponent两个组件都根据自己的情况扩展和提供它。这样,每当有人尝试注射时ShapeComponent,他们都会得到 aLineComponent或 a ShapeComponent

最后,让我们创建一个ShapeHolderComponent将所有这些粘合在一起的

@Component({
  selector: 'shape-holder',
  template: `
    <div *ngFor="let child of children">
      <ng-container *ngTemplateOutlet="child.template"></ng-container>
    </div>
  `,
})
export class ShapeHolderComponent  {

  @ContentChildren(ShapeComponent) children: QueryList<ShapeComponent>;
} 
Run Code Online (Sandbox Code Playgroud)

您可以使用 列出ShapeComponents ContentChildren。因为每个都ShapeComponent提供了自己,所以我们可以获得它们的列表并使用它们template

最后,让我们在其中使用所有这些AppComponent

<shape-holder>
  <circle>
    Custom Circle content
  </circle>
  <line>
    Custom Line content
  </line>
</shape-holder>
Run Code Online (Sandbox Code Playgroud)

输出是

This is circle and its content: Custom Circle content
This is line and its content: Custom Line content
Run Code Online (Sandbox Code Playgroud)


sla*_*dan 1

有一个显示组件的解决方案,但它相当复杂,不是我的推荐。

您的问题的“角度风格”解决方案是这样的:

  1. 使用模型对象(不是组件)列表,其中包含子组件所需的所有信息。我们models在这个例子中调用它。
  2. 将形状的类型存储在每个模型的属性中(避免必须使用typeOf)。让我们调用 if shape。如果您愿意,也可以使用枚举。
  3. 迭代 a 中的模型ngFor并为每个模型创建一个组件。

HTML 模板可能如下所示

<div *ngFor="let model of models">

    <!-- display the ng-template from for example LineComponent or Circle -->
    <line   [model]="model" *ngIf="model.shape === 'Line'"></line>
    <circle [model]="model" *ngIf="model.shape === 'Circle'"></circle>

</div>
Run Code Online (Sandbox Code Playgroud)

请参阅stackblitz 上完整的工作示例。