首页 文章

在ngFor中动态添加组件

提问于
浏览
8

我有一个“仪表板”,可以加载配置的元素 . 仪表板模板具有:

<div class="dash-container" [ngGrid]="gridConfig">
    <div *ngFor="let box of boxes; let i = index"
       [(ngGridItem)]="box.config"
       (onItemChange)="updateItem(i, $event)"
       (onResize)="onResize(i, $event)"
       (onDrag)="onDrag(i, $event)"
       (onDragStop)="onDragStop(i,$event)"
       [ngClass]="box.class"
     >
      <div class="handle"><h4>{{box.title}}</h4></div>
      <div [innerHTML]= "box.content"></div>
    </div>
  </div>

现在 <div [innerHTML]= "box.content"></div> 将无效,因为非标准元素已被清理 . 运行最新的Angular 2.4.6(RC 6) .

我看一下我能找到的动态组件的例子 - 但我所看到的只是他们只是将组件添加到当前组件 - 但我需要它们在一个非常特定的div中,如上例所示 .

ComponentFactoryResolver 通常与 @ViewChild 一起使用 . 但我不能在一个循环中这样做:

ngAfterViewInit() {
    const dashWidgetsConf = this.widgetConfigs();
    for (var i = 0; i < dashWidgetsConf.length; i++) {
      const conf = dashWidgetsConf[i];

      @ViewChild(conf.id, {read: ViewContainerRef}) var widgetTarget: ViewContainerRef;

      var widgetComponent = this.componentFactoryResolver.resolveComponentFactory(UnitsComponent);
      widgetTarget.createComponent(widgetComponent);
    }
  }

@viewchild给出'Decorators are not valid here' . 如何从conf列表中加载组件(在循环中)并将它们添加到我的组件中的特定div(divs #{{conf.id}} )中?

2 回答

  • 12

    经过一番研究,这是我提出的解决方案(工作在角4.0.0) .

    按ID加载所有 ViewContainerRef 目标:

    @ViewChildren('dynamic', {read: ViewContainerRef}) public widgetTargets: QueryList<ViewContainerRef>;
    

    然后遍历它们以获取目标,为组件创建工厂并调用 createComponent .
    也可以使用组件引用来订阅或设置其他组件属性 .

    ngAfterViewInit() {
        const dashWidgetsConf = this.widgetConfigs();
        const widgetComponents = this.widgetComponents();
        for (let i = 0; i < this.widgetTargets.toArray().length; i++) {
            let conf = dashWidgetsConf[i];
            let component = widgetComponents[conf.id];
            if(component) {
                let target = this.widgetTargets.toArray()[i];
                let widgetComponent = this.componentFactoryResolver.resolveComponentFactory(component);
                let cmpRef: any = target.createComponent(widgetComponent);
    
                if (cmpRef.instance.hasOwnProperty('title')) {
                    cmpRef.instance.title = conf.title;
                }
            }
        }
    }
    

    widgetComponents 是一个对象 {key: component}widgetConfigs 是我存储特定组件信息的地方 - 如 Headers ,组件ID等 .

    然后在模板中:

    <div *ngFor="let box of boxes; let i = index" >
        <ng-template #dynamic></ng-template>
    </div>
    

    目标的顺序与我的conf中的顺序相同( boxes 是从它生成的) - 这就是为什么我可以按顺序循环它们并使用i作为索引来获得正确的conf和组件 .

  • 1

    if (cmpRef.instance.hasOwnProperty('title')) {
       cmpRef.instance.title = conf.title;
    }
    

    您可以添加 this.cd.detectChanges(); ,否则您的子组件中将出现错误"ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked"与Angular 6x .

相关问题