【问题标题】:Render Component Dynamically动态渲染组件
【发布时间】:2019-08-18 22:54:57
【问题描述】:

我有这个数组:

this.dashboard = [
     {name: '<app-incassi-provvigioni></app-incassi-provvigioni>'},
     {name: '<app-scheda-punti-vendita></app-scheda-punti-vendita>'}
]

我在 ngOnInit 循环中填充这个数组。 我想知道当我像这样在 html 中读取数组时如何渲染组件:

<gridster [options]="gridsterOptions">
    <gridster-item [item]="item" *ngFor="let item of dashboard">
        <!-- your content here -->
        {{item.name}}
    </gridster-item>
</gridster>

当然,现在它返回包含在对象中的字符串,但我正在尝试找到一种解决方案来呈现组件。 有可能吗?

更多详情: 我正在开发一个仪表板类型的应用程序,我在其中从数据库中检索用户仪表板列表,并且我试图在主应用程序组件准备好后动态呈现这些组件。 使用 Angular 7 和 Gridster2。

【问题讨论】:

  • &lt;div [innerHTML]="item.name"&gt;&lt;/div&gt;....呢?
  • @Edison 它在 dashlet 容器内创建了一个空的 div。它没有渲染组件。
  • Angular 有一个非常好的使用动态组件的指南。我认为你应该参考这个:angular.io/guide/dynamic-component-loader
  • 所以所有字符串 (component-selectors) 都是同一个模块的一部分?
  • 为什么要使用标签?!为什么不使用 CompnentClass 作为数组中的元素。这将使组件加载器工厂更容易。

标签: angular typescript dashboard gridster


【解决方案1】:

而是传递组件标签名称(在您的情况下为“app-incassi-provvigioni”),传递组件名称(TestComponenet),然后从您的视图中调用该函数并使用指令动态呈​​现它。

例如:

<gridster [options]="gridsterOptions">
  <gridster-item [item]="item" *ngFor="let item of dashboard">
    <div class="inner">
      <ng-template dynamic-template> </ng-template>
    </div>
  </gridster-item>
</gridster>

dynamic-template 是一个指令,帮助我们加载组件。

【讨论】:

  • 这听起来很有趣,你能提供一些代码示例吗?
  • @LucaAlberto,我刚刚通过示例代码检查了链接:[link] (stackblitz.com/edit/angular-yz8w1u)。如果这适合您,请标记为答案。谢谢
  • 伙计,你拯救了我的一天。这个答案应该是公认的答案。
【解决方案2】:

可以注入组件dynamically

只需使用@Input() 组件创建组件;

export class DynamicContentComponent implements OnInit {

  @Input() component: any;
  @Input() data: any;

  constructor(public viewContainerRef: ViewContainerRef,
              private componentFactoryResolver: ComponentFactoryResolver) { }

  ngOnInit() {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.component);
    this.viewContainerRef.clear();

    const componentRef = this.viewContainerRef.createComponent(componentFactory);
    (<DynamicComponentRef>componentRef.instance).data = this.data;
  }
}

并在 HTML 中使用它

<app-dynamic-content [component]="someComponent" [data]="data"></app-dynamic-content>

数据示例

someComponent = SchedaPuntiVendita;

应将动态组件添加到您的module 中的entryComponents

您还可以创建某种factory,它将接收一些字符串并取决于它返回您的组件类

工厂示例

@Injectable()
export class DynamicContentComponentFactory {

  constructor() { }

  get(type: ContentType): any {
    switch (type) {
      case 'scheda':
        return SchedaPuntiVendita;
    }
  }

并稍微修改DynamicContentComponent

@Input() contentType: string;

constructor(..., private factory: DynamicContentComponentFactory) { }
...

const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.factory.get(this.contentType));

...

【讨论】:

  • 不再需要 ComponentFactoryResolver。 Angular 团队对其进行了精简,因此您可以像这样直接创建组件:this.viewContainerRef.createComponent(this.component);
【解决方案3】:

也许您可以为此使用角度开关:

<div [ngSwitch]="item.name">
    <app-incassi-provvigioni *ngSwitchCase="incassi"></app-incassi-provvigioni>
    <app-scheda-punti-vendita *ngSwitchCase="scheda"></app-scheda-punti-vendita>
</div>

【讨论】:

    【解决方案4】:
    this.dashboard = [
             {name: 'dashboard1'},
             {name: 'dashboard2'}
        ]
    
        <gridster [options]="gridsterOptions">
            <gridster-item [item]="item" *ngFor="let item of dashboard">
                <ng-container *ngIf="item.name === 'dashboard1'" *ngTemplateOutlet="dashboard1">
                </ng-container>
                <ng-container *ngIf="item.name === 'dashboard1'" *ngTemplateOutlet="dashboard2">
                </ng-container>
            </gridster-item>
        </gridster>
    
    
        <ng-template #dashboard1>
            <app-incassi-provvigioni></app-incassi-provvigioni>
        </ng-template>
        <ng-template #dashboard2>
            <app-scheda-punti-vendita></app-scheda-punti-vendita>
        </ng-template>
    

    【讨论】: