Angular CDK:如何在ComponentPortal中设置输入

时间:2017-11-24 09:12:39

标签: angular angular-material2 angular-cdk

我想使用材质CDK中的新Portal将动态内容注入表单的多个部分。

我有一个复杂的表单结构,目标是有一个表单,指定子组件可以(或不)注入模板的多个位置。

也许CDK门户网站不是最好的解决方案吗?

我尝试了一些东西,但我确信这不是做法: https://stackblitz.com/edit/angular-yuz1kg

我也尝试使用new ComponentPortal(MyPortalComponent),但我们如何在其上设置输入?通常类似于componentRef.component.instance.myInput

6 个答案:

答案 0 :(得分:19)

您可以创建自定义注入器并将其注入您创建的组件门户。 -

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

CONTAINER_DATA是由

创建的自定义注入器(InjectorToken
export const CONTAINER_DATA = new InjectionToken<{}>('CONTAINER_DATA');

要使用创建的注入器,请使用 -

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

overlay.attach(containerPortal);

overlayOverlayRef(Portal Outlet)的实例

ComponentToPort内,您需要注入创建的注入器 -

@Inject(CONTAINER_DATA) public componentData: any

此处有更多相关信息 -

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

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

答案 1 :(得分:8)

如果您使用的是Angular 10以及Awadhoot's answer之后的版本,则不建议使用PortalInjector,而不是:

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

您现在拥有:

Injector.create({
  parent: this.injector,
  providers: [
    { provide: SOME_TOKEN, useValue: data }
  ]
})

答案 2 :(得分:6)

您可以使用在Not Found

第三参数上传递的特定注入器将数据注入ComponentPortal

修复语法问题

ComponentPortal

这是代码

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

答案 3 :(得分:5)

使用cdkPortalOutlet和(附加的)发射器

,这似乎更简单。
import {Component, ComponentRef, AfterViewInit, TemplateRef, ViewChild, ViewContainerRef, Input, OnInit} from '@angular/core';
import {ComponentPortal, CdkPortalOutletAttachedRef, Portal, TemplatePortal, CdkPortalOutlet} from '@angular/cdk/portal';

/**
 * @title Portal overview
 */
@Component({
  selector: 'cdk-portal-overview-example',
  template: '<ng-template [cdkPortalOutlet]="componentPortal" (attached)=foo($event)></ng-template>',
  styleUrls: ['cdk-portal-overview-example.css'],
})
export class CdkPortalOverviewExample implements OnInit {
  componentPortal: ComponentPortal<ComponentPortalExample>;

  constructor(private _viewContainerRef: ViewContainerRef) {}

  ngOnInit() {
    this.componentPortal = new ComponentPortal(ComponentPortalExample);
  }

  foo(ref: CdkPortalOutletAttachedRef) {
    ref = ref as ComponentRef<ComponentPortalExample>;
    ref.instance.message = 'zap';
  }
}

@Component({
  selector: 'component-portal-example',
  template: 'Hello, this is a component portal {{message}}'
})
export class ComponentPortalExample {
  @Input() message: string;
}

答案 4 :(得分:3)

可以通过以下方式设置组件输入(或以可见的方式绑定到输出):

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

答案 5 :(得分:2)

不建议使用角度9版本“ DomPortalHost”,并将其更改为“ DomPortalOutlet”。所以现在它将是:

this.portalHost = new DomPortalOutlet(
   this.elementRef.nativeElement,
   this.componentFactoryResolver,
   this.appRef,
  this.injector
);

const componentRef = this.portalHost.attachComponentPortal(this.portal); componentRef.instance.myInput = data;

除此之外,我觉得最好的解决方案是绑定(附加)事件并在那里设置输入:

<ng-template [cdkPortalOutlet]="yourPortal" (attached)="setInputs($event)"> </ng-template>

并在ts中设置您的输入:

setInputs(portalOutletRef: CdkPortalOutletAttachedRef) {
    portalOutletRef = portalOutletRef as ComponentRef<myComponent>;
    portalOutletRef.instance.inputPropertyName = data;
}