4

I have some code that dynamically adds/removes components to one of my pages. That seems to work fine and I based the method on Rob Wormald's awesome Ng2 Advanced Talk.

Doing things in that standard way looks like this:

@Component({
    template: `
    <parent-component>
       <template #dyn_target></template>
    </parent-component>
    `
 })
 export class MyComp {
     @ViewChild('dyn_target', {read: ViewContainerRef}) myTarget;

     constructor(protected cfr: ComponentFactoryResolver) {}

     ngOnInit(): void {
        const factory = this.cfr.resolveComponentFactory(DynComp);
        const compRef = this.myTarget.createComponent(factory);
     }
 }

Everything is happy and works. But now my question is how do I do something like this if the target location for the component is an element that is itself inside an *ngIf? I have code that knows when the *ngIf should be showing the new elements, but I don't know how to lookup the ViewContainerRef for the target inside of the *ngIf.

@Component({
    template: `
    <parent-component>
       <other-comp></other-comp>
       <div *ngIf="showMe"
           <nested-comp>
              <template #dyn_target></template>
           </nested-comp>
       </div>

    </parent-component>
    `
 })
 export class MyComp {
     @ViewChild('dyn_target', {read: ViewContainerRef}) myTarget;
     showMe: boolean = false;

     constructor(protected cfr: ComponentFactoryResolver) {}

     addDynComponent(): void {
        // Q: how do I do this?           vv
        const target: ViewContainerRef = lookup('dyn_target');
        const factory = this.cfr.resolveComponentFactory(DynComp);
        const compRef = target.createComponent(factory);
     }
 }

I thought about trying to remove the ngIf and make the entire block dynamic, but that doesn't really work for my case because most of the content is static, there is just one subcomponent that needs to be added when/if the ngIf is true.

Anyone know how to find a ViewContainerRef on the fly after the ngIf adds the other elements to the DOM?

Note: another way I thought about doing this is to add a new component type that just shows a nested component based upon an input of a component class type. I have seen that type of thing done for Ionic 2 and it would probably work in my case but seems like overkill. So something like:

@Component({
    template: `
    <parent-component>
       <other-comp></other-comp>
       <div *ngIf="showMe"
           <nested-comp>
              <show-comp [compClass]="dynClass"></show-comp>
           </nested-comp>
       </div>

    </parent-component>
    `
 })
 export class MyComp {
     dynClass: any;
     showMe: boolean = false;

     addDynComponent(): void {
        dynClass = DynComp;
     }
 }

1 Answer 1

6

I think this should work

@ViewChildren('dyn_target', {read: ViewContainerRef}) myTarget:QueryList<ViewContainerRef>;

ngAfterViewInit() {
  this.myTarget.changes.subscribe(changes => {
    if(this.myTarget.toArray().length) {
      // myTarget ViewContainerRef available
    }
  });
}
Sign up to request clarification or add additional context in comments.

3 Comments

Right, fixed. Thanks.
Is there any way to run the view query directly without using the @ViewChildren property decorator? I have been trying to find the code that ViewChildren calls to do this query but haven't had much luck. :(
Don't think so. I guess it's part of the compiler.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.