如何在Angular [cdkPortalOutlet]

时间:2018-08-11 19:38:06

标签: angular angular-material2

Angular Material(CDK)中的Portal模块是一种非常强大的方法,可以将动态内容呈现到“ PortalOutlet”中。

Portal<T>可以是TemplateRef,其中T是上下文数据的类型。

<ng-template cdkPortal let-data>
    <p>Portal contents {{ data | json }}</p>
</ng-template>

您可以使用@ViewChild

对其进行引用
@ViewChild(CdkPortal) myPortalRef: CdkPortal;  

您可以在cdkPortalOutlet

中显示门户
Content gets inserted here: 
<ng-template [cdkPortalOutlet]="myPortalRef"></ng-template>

这会将门户内容插入出口。

但是提供的指令缺少两个主要功能。

1) no way to set the actual context object on the outlet using the directive
2) no way to set the context object on the portal itself

您可以手动创建门户并提供上下文,也可以使用上下文以编程方式将门户附加到PortalOutlet,但是我想声明性地做到这一点。

相似的[NgTemplateOutlet]确实为[ngTemplateOutletContext]提供了一个属性。

在CdkPortal上设置上下文的最佳方法是什么?我应该自己扩展指令,还是尝试通过服务传递数据?我以为这个模块的重点是使事情变得超级简单。

Angular source

另请参阅:https://github.com/angular/material2/issues/6310

2 个答案:

答案 0 :(得分:2)

我也遇到了同样的问题,最终以为我们实际上是从错误的角度考虑这个问题!

仅当我们具有要进行投影的模板时,注入上下文才有意义。在这种情况下,变量将添加到模板环境中,并且可以将它们绑定到模板代码中的组件属性:

<ng-template #user_details let-user>
  <qtl-manage-user-panel [user]="user"></qtl-manage-user-panel>
</ng-template>

但是如果没有ng-template(即Portal的情况),那会觉得很奇怪。目标组件将具有开箱即用的上下文,而没有let指令。它将绑定到什么变量?

因此,回到我们将实际组件投影到Portal中的案例:如何传递上下文?最好的答案是我认为注射

上下文将在构建时通过自定义Injector传递到组件的构造函数。要做的就是创建自定义注入令牌:

export const MY_TOKEN = new InjectionToken<TTT>('xxx');

然后,在创建ComponentPortal时,我们提供一个自定义的注入器:

const injector =
Injector.create({
  providers: [
    {
      provide: MY_TOKEN,
      useValue: /* Here, the context variable */,
    },
  ]});

const cPortal = new ComponentPortal(ComponentClass, null, injector);

这样,上下文变量将被注入到ComponentClass构造函数中,并且可以通过以下方式访问:

constructor(
    @Inject(MY_TOKEN) public context: CCC,
  ) { ... }

现在context可以在组件类或模板中使用。

聚会晚了一点,但我希望它可以帮助将来解决这个问题的人们。

答案 1 :(得分:1)

我认为您可以直接将上下文分配给门户,但是我尚未对此进行测试。必须在出口使用门户之前对其进行分配,这可能很棘手。

@ViewChild(CdkPortal) myPortalRef: CdkPortal;  

public ngAfterViewInit(): void {
    this.myPortalRef.context = {...}; // your context data
}

我认为这里的问题是上下文是附加到门户的,而不是独立的。因此,您不能使用同一门户在具有两个不同上下文的两个不同出口中进行渲染。

还,您是否尝试过将cdkPortalOutlet与Angular中的微语法解析器一起使用,以查看其是否有效?

<ng-template *cdkPortalOutlet="myPortalRef; context: contextExp"></ng-template>

据我所知,门户网站中没有使用ng-template方法。带有门户网站的所有内容都是作为服务完成的,并且模板变体似乎已成为社区的附加功能,但尚未完全经过审查。