Dynamically adding components in ngFor

后端 未结 4 920
感情败类
感情败类 2020-12-08 11:33

I have a \"dashboard\" that loads configured elements. Dashboard template has this:

  
相关标签:
4条回答
  • 2020-12-08 11:47

    After

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

    You can add this.cd.detectChanges(); or you will have the error "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked" in your children component with Angular 6x.

    0 讨论(0)
  • 2020-12-08 11:49

    If you have this pattern:

    <div *ngFor="for item in items">
      <!-- needs to be one per item -->
      <ng-template details-directive></ng-template>
    </div>
    

    I suggest wrapping the directive in a component:

    @Component({
      selector: 'details-wrapper',
      template: '<ng-template details-directive></ng-template>'
    })
    export class DetailsWrapper {
      @Input item?: Item;
      // Dynamically load details using the regular solution.
    }
    

    And making this your for loop:

    <div *ngFor="for item in items">
      <details-wrapper [item]="item"></details-wrapper>
    </div>
    
    0 讨论(0)
  • 2020-12-08 11:51

    After some research, this is the solution i came up with (works in angular 4.0.0).

    Load all the ViewContainerRef targets by id:

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

    Then loop over them to get the target, create a factory for the component and call createComponent.
    Also can use the component reference to subscribe or set other component properties.

    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;
                }
            }
        }
    }
    

    The widgetComponents is a object {key: component} and widgetConfigs is where i store specific component info - like title, component id etc.

    Then in template:

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

    And the order of targets is the same as in my conf ( boxes is generated from it) - which is why i can loop through them in order and use i as index to get the correct conf and component.

    0 讨论(0)
  • 2020-12-08 11:54

    I resolved the issue by adding 'static: false'.

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

    https://stackoverflow.com/a/41095677/6329980

    0 讨论(0)
提交回复
热议问题