Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Parent ViewContainerRef from inside projected child component Angular 5

I have an App component with dynamically created components. Parent component has an <ng-content> element so that we can project our child components inside the Parent component.

App Component:

@Component({
  selector: 'my-app',
  template:`<ng-container #parentcontainer></ng-container>`,
})

Parent component:

@Component({
  selector: 'parent',
  template: `
  <ng-container #container></ng-container>
  <ng-content></ng-content>

                `
})

Child Component:

@Component({
  selector: 'child',
  template: `<label>
                <input type="radio">
              </label>
                `
})

My question is, is there any way to access the App component's ViewContainerRef (#parentcontainer) inside Child component ? Goal is to dynamically insert other components inside #parentcontainer, at a later stage, like on some button click from Child Component.

Here is the working sample on StackBlitz

like image 532
user636525 Avatar asked Mar 07 '23 08:03

user636525


1 Answers

You can create a new component from within the child component, and attach it's HTML element anywhere you like in the DOM

// remember to add YourComponent to entryComponents: [] of the module
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(YourComponent);
let componentRef = viewContainerRef.createComponent(componentFactory, index);

componentRef.instance.model = model; // where model is an input
componentRef.changeDetectorRef.detectChanges(); // update it's view
let htmlElement = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement;

// Now do what you want with the htmlElement e.g. document.querySelector('body').appendChild(htmlElement)

Would that work for you? Note, that the component will only stay alive for as long as the Child Component is alive

Alternatively, to keep the components alive for the app duration, create a service and provide it once at the AppComponent level. Note that this uses the ApplicationRef, which allows you to call attachView() - this might be a solution

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

  appendComponentToBody(component: any) {
    const componentRef = this.componentFactoryResolver
      .resolveComponentFactory(component)
      .create(this.injector);    
    this.appRef.attachView(componentRef.hostView);
    const domElem = (componentRef.hostView as EmbeddedViewRef<any>)
      .rootNodes[0] as HTMLElement;    
    // Append to body or wherever you want
    document.body.appendChild(domElem);
  }

There's more details on the Service example here

The best solution is probably to use the Angular Material CDK functionality for Portal and PortalHost. It's pretty new, but it's purpose is to create components from within an Angular app that run outside of the actual my-app element - this might be a better long term solution - it's used for making modals etc in their examples

like image 136
Drenai Avatar answered Mar 18 '23 15:03

Drenai