Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular CDK: How to set Inputs in a ComponentPortal

I would like to use the new Portal from material CDK to inject dynamic content in multiple part of a form.

I have a complex form structure and the goal is to have a form that specify multiple place where sub components could (or not) inject templates.

Maybe the CDK Portal is not the best solution for this?

I tried something but I am sure it is not the way of doing: https://stackblitz.com/edit/angular-yuz1kg

I tried also with new ComponentPortal(MyPortalComponent) but how can we set Inputs on it ? Usually is something like componentRef.component.instance.myInput

like image 702
JoG Avatar asked Nov 24 '17 09:11

JoG


2 Answers

You can create a custom injector and inject it to the component portal you create.

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 created injector, use -

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

overlay is an instance of OverlayRef (Which is Portal Outlet)

Inside ComponentToPort, you will need to inject the created injector -

@Inject(CONTAINER_DATA) public componentData: any 

More on this here.

like image 112
Awadhoot Avatar answered Oct 09 '22 02:10

Awadhoot


If you are using Angular 10+ and following Awadhoot's answer, PortalInjector is now deprecated so instead of:

new PortalInjector(this.injector, new WeakMap([[SOME_TOKEN, data]])) 

You now have:

Injector.create({   parent: this.injector,   providers: [     { provide: SOME_TOKEN, useValue: data }   ] }) 
like image 26
Wildhammer Avatar answered Oct 09 '22 01:10

Wildhammer