Angular CDK: How to Set Inputs in ComponentPortal

I would like to use the new portal from the CDK material to add dynamic content to several parts of the form.

I have a complex form structure, and the goal is to have a form indicating several places where subcomponents can (or not) implement templates.

Maybe CDK Portal is not the best solution for this?

I tried something, but I'm sure it is not: https://stackblitz.com/edit/angular-yuz1kg

I tried also with new ComponentPortal(MyPortalComponent) but how can we set the inputs to it? This is usually something like componentRef.component.instance.myInput

+14
angular angular-material2 angular-cdk
source share
3 answers

You can create your own injector and embed it in the component portal you created. -

 createInjector(dataToPass): PortalInjector { const injectorTokens = new WeakMap(); injectorTokens.set(CONTAINER_DATA, dataToPass); return new PortalInjector(this._injector, injectorTokens); } 

CONTAINER_DATA is a custom injector (InjectorToken) created by -

 export const CONTAINER_DATA = new InjectionToken<{}>('CONTAINER_DATA'); 

To consume the created injector, use -

  let containerPortal = new ComponentPortal(ComponentToPort, null, this.createInjector({ data1, data2 })); overlay.attach(containerPortal); 

the overlay is an instance of OverlayRef (which is the exit portal)

Inside the "ComponentToPort" you will need to enter the created injector -

 @Inject(CONTAINER_DATA) public componentData: any 

More about this here -

  1. https://github.com/angular/material2/issues/8322

  2. https://github.com/angular/material2/issues/8322

+13
source share

You can enter data into ComponentPortal using a special injector passed in the 3rd parameter of ComponentPortal (fix syntax problem: it is impossible to resolve all parameters for a component: ([object of an object], [object of an object] ,?).

 export const PORTAL_DATA = new InjectionToken<{}>('PortalData'); class ContainerComponent { constructor(private injector: Injector, private overlay: Overlay) {} attachPortal() { const componentPortal = new ComponentPortal( ComponentToPort, null, this.createInjector({id: 'first-data'}) ); this.overlay.create().attach(componentPortal); } private createInjector(data): PortalInjector { const injectorTokens = new WeakMap<any, any>([ [PORTAL_DATA, data], ]); return new PortalInjector(this.injector, injectorTokens); } } class ComponentToPort { constructor(@Inject(PORTAL_DATA) public data ) { console.log(data); } } 
+3
source share

You can set component inputs (or bind to outputs as observables) as follows:

 portal = new ComponentPortal(MyComponent); this.portalHost = new DomPortalHost( this.elementRef.nativeElement, this.componentFactoryResolver, this.appRef, this.injector ); const componentRef = this.portalHost.attach(this.portal); componentRef.instance.myInput = data; componentRef.instance.myOutput.subscribe(...); componentRef.changeDetectorRef.detectChanges(); 
0
source share

All Articles