如何在 Angular [cdkPortalOutlet] 上设置上下文

Sim*_*ver 5 angular-material2 angular

Angular Material (CDK) 中的Portal模块是一种非常强大的将动态内容渲染到“PortalOutlet”的方式。

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

<ng-template cdkPortal let-data>
    <p>Portal contents {{ data | json }}</p>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

你得到一个参考 @ViewChild

@ViewChild(CdkPortal) myPortalRef: CdkPortal;  
Run Code Online (Sandbox Code Playgroud)

您可以在 cdkPortalOutlet

Content gets inserted here: 
<ng-template [cdkPortalOutlet]="myPortalRef"></ng-template>
Run Code Online (Sandbox Code Playgroud)

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

但是提供的指令有两个重要的缺失功能。

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
Run Code Online (Sandbox Code Playgroud)

您可以手动创建门户并提供上下文,或者使用上下文以编程方式将门户附加到 PortalOutlet,但我想以声明方式进行。

类似的(并且更常用)[NgTemplateOutlet]确实为 提供了一个属性[ngTemplateOutletContext]

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

角源

另见:https : //github.com/angular/material2/issues/6310

Mic*_*Mic 8

我也遇到过同样的问题,最后我想我们实际上是从错误的角度来看待这个问题的!

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

<ng-template #user_details let-user>
  <qtl-manage-user-panel [user]="user"></qtl-manage-user-panel>
</ng-template>
Run Code Online (Sandbox Code Playgroud)

但如果没有ng-template(即案例Portal),那就会感觉很奇怪。目标组件将具有开箱即用的上下文,无需let指令。它应该绑定到哪些变量?

那么,回到我们将实际组件投影到门户中的情况:如何传递上下文?我认为最好的答案是注射。

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

export const MY_TOKEN = new InjectionToken<TTT>('xxx');
Run Code Online (Sandbox Code Playgroud)

然后,在创建时ComponentPortal,我们给出一个自定义注入器:

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

const cPortal = new ComponentPortal(ComponentClass, null, injector);
Run Code Online (Sandbox Code Playgroud)

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

constructor(
    @Inject(MY_TOKEN) public context: CCC,
  ) { ... }
Run Code Online (Sandbox Code Playgroud)

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

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


Rea*_*lar 3

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

@ViewChild(CdkPortal) myPortalRef: CdkPortal;  

public ngAfterViewInit(): void {
    this.myPortalRef.context = {...}; // your context data
}
Run Code Online (Sandbox Code Playgroud)

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

另外,您是否尝试过cdkPortalOutlet在 Angular 中使用微语法解析器来看看它是否有效?

<ng-template *cdkPortalOutlet="myPortalRef; context: contextExp"></ng-template>
Run Code Online (Sandbox Code Playgroud)

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