Angular CDK: How to set Inputs in a ComponentPortal

送分小仙女□ 提交于 2019-12-18 11:04:29

问题


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


回答1:


You can create 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 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 -

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

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




回答2:


Can set component inputs (or bind to outputs as an observable) in this way:

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();



回答3:


You can inject data to ComponentPortal with specific injector passed on 3rd param of ComponentPortal

fix syntax issue:

Can't resolve all parameters for Component: ([object Object], [object Object], ?

This is the code

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);
  }
}


来源:https://stackoverflow.com/questions/47469844/angular-cdk-how-to-set-inputs-in-a-componentportal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!