@ViewChild(CdkPortalOutlet) returns 在 AfterViewInit 中未定义

@ViewChild(CdkPortalOutlet) returns undefined in AfterViewInit

尝试用 CdkPortalOutlet 查询 ng-template 总是不成功,我不明白为什么?

<ng-template CdkPortalOutlet></ng-template>

@ViewChild(CdkPortalOutlet) test: CdkPortalOutlet;

stackblitz

为了在 AppComponent 模板中使用 CdkPortalOutlet 指令,您必须在 AppModule 中导入 PortalModule(即已声明 AppComponent 的 NgModule)

import { PortalModule } from '@angular/cdk/portal';
...

@NgModule({
  imports:      [ BrowserModule, FormsModule, PortalModule, OverlayModule ],
                                              ^^^^^^^^^^^^
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})

export class AppModule { }

此外,Angular HTML 解析器区分大小写,因此您需要像这样使用它:

<ng-template cdkPortalOutlet></ng-template>
             ^^^
          lower case

Forked Stackblitz

因为 Angular 8 @ViewChild 需要提供一个额外的 static 参数,并且很难找到关于将其设置为什么值的文档。如果设置不正确,当尝试使用 @ViewChild.

检索 CdkPortalOutlet 时,将导致 undefined

TLDR

迁移到 Angular 8.

时设置 @ViewChild(CdkPortalOutlet, { static: true })

从 Angular 代码中提取注释

如何选择要使用的 static 标志值:truefalse

对于内容查询,我们一直建议在 ngAfterContentInit 中检索查询结果。 这是因为到这个生命周期钩子 运行s 时,相关节点的变化检测已经完成,我们可以保证我们已经收集了所有可能的查询结果。

出于这个原因,大多数应用程序都希望使用 {static: false}。此设置将确保查询找到依赖于绑定解析的查询匹配项(例如 *ngIfs 或 *ngFors 内的结果)。 如果您需要访问查询中的 TemplateRef 以动态创建视图,则无法在 ngAfterContentInit 中执行此操作。 更改检测已经对该视图进行了 运行,因此使用模板创建新视图将导致抛出 ExpressionHasChangedAfterChecked 错误。 在这种情况下,您需要将 static 标志设置为 true 并在 ngOnInit 中创建您的视图。 在大多数其他情况下,最佳做法是使用 {static: false}.

但是,为了便于迁移到版本 8,如果您的组件代码已经依赖于某个时间可用的查询结果,您可能还需要将 static 标志设置为 true 之前ngAfterContentInit。 例如,如果您的组件依赖于在 ngOnInit 挂钩或 @Input 设置器中填充的查询结果,则您需要将标志设置为 true 或 re-work您的组件以适应以后的计时。

注意:选择静态选项意味着查询不会找到嵌套在*ngIf*ngFor中的查询结果。 这些结果只能在更改检测 运行 秒后检索。