Search code examples
angularangular-material2angular-cdk

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


Solution

  • 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.