Chris
Chris

Reputation: 461

Angular 2+ Create ViewRef from Markup Injected into Dynamic Template

I would like to create a ViewRef from markup that is dynamically inserted into a template. Is this possible based on the following code sample?

template.html:

<ng-container *ngTemplateOutlet="dynamic; context: cntx"></ng-container>
<ng-template #dynamic>
  <div [innerHTML]="markup"></div>
</ng-template>

Injected markup from API call to bind to div's innerHTML attribute:

<div>
    <div id="forViewRef"></div>
</div>

component.ts:

@ContentChild('#forViewRef', { read: ViewContainerRef }): someHndl;
private _nativeElem: any;

constructor(
    private sanitizer: DomSanitizer, 
    private _vcRef: ViewContainerRef, 
    private _resolver: ComponentFactoryResolver) {
    // to ensure template has been created, #dynamic
    this._nativeElem = this._vcRef.element.nativeElement;
}

// listen to lifecycle hook
ngAfterContentChecked() {
    if (this._nativeElem !== undefined)
        // childContent ref is undefined
        console.log(this.someHndl);
        // markup is in the DOM
        console.log(this._nativeElem.querySelectorAll('#forViewRef'));
}

Upvotes: 0

Views: 4333

Answers (1)

yurzui
yurzui

Reputation: 214175

To create component dynamically inside <div id="forViewRef"></div> you can do the following:

Let's say we need to load the following component

@Component({
  selector: 'dynamic-comp',
  template: `
   <h2>Dynamic component</h2>
    <button (click)="counter = counter + 1">+</button> {{ counter }}
  `
})
export class DynamicComponent {
  counter = 1;
}

so first add it to declarations and entryComponents array of your @NgModule

  ...
  declarations: [ ..., DynamicComponent ],
  entryComponents: [ DynamicComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

after that create

template.html

<button (click)="createComponent()">Create component</button>

<div id="forViewRef"></div>

and finally write

component.ts

export class AppComponent {
  compRef: ComponentRef<DynamicComponent>;

  constructor(private injector: Injector,
              private resolver: ComponentFactoryResolver,
              private appRef: ApplicationRef) {}


  createComponent() {
    const compFactory = this.resolver.resolveComponentFactory(DynamicComponent);
    this.compRef = compFactory.create(this.injector, null, '#forViewRef');

    this.appRef.attachView(this.compRef.hostView);
  }

  ngOnDestroy() {
    if(this.compRef) {
      this.compRef.destroy();
    }
  }
}

I use appRef.attachView in order to include dynamic component to change detection cycle

Plunker Example

See also

Upvotes: 3

Related Questions