无法读取属性' viewContainerRef'未定义的

时间:2018-01-18 21:40:11

标签: angular angular-directive angular-components

我正在尝试显示与angular docs中的示例相似(不完全)的动态组件。

我有一个带有viewContainerRef的动态指令

SELECT
    name,
    SUM(CASE WHEN drunk = 'Y' THEN 1 ELSE 0 END) as drunk,
    SUM(CASE WHEN awake = 'Y' THEN 1 ELSE 0 END) as awake
FROM
    tb1
GROUP BY
    name

摘录组件代码

@Directive({
   selector: '[dynamicComponent]'
})
export class DynamicComponentDirective {
   constructor(public viewContainerRef: ViewContainerRef) { }
}

最后在模板中添加了@ViewChild(DynamicComponentDirective) adHost: DynamicComponentDirective; .. ngAfterViewInit() { let componentFactory = null; console.log(component); componentFactory = this.componentFactoryResolver.resolveComponentFactory(component); // this.adHost.viewContainerRef.clear(); const viewContainerRef = this.adHost.viewContainerRef; viewContainerRef.createComponent(componentFactory); }

9 个答案:

答案 0 :(得分:14)

你可以采用这种方法: 不要创建指令,而是将ID提供给ng-template

<ng-template #dynamicComponent></ng-template>

在组件类中使用@ViewChild装饰器

@ViewChild('dynamicComponent', { read: ViewContainerRef }) myRef

ngAfterViewInit() {
    const factory = this.componentFactoryResolver.resolveComponentFactory(component);
    const ref = this.myRef.createComponent(factory);
    ref.changeDetectorRef.detectChanges();
}

答案 1 :(得分:5)

我遇到了同样的问题。您必须将指令添加到AppModule:

 @NgModule({
  declarations: [
    AppComponent,
    ...,
    YourDirective,
  ],
  imports: [
   ...
  ],
  providers: [...],
  bootstrap: [AppComponent],
  entryComponents: [components to inject if required]
})

答案 2 :(得分:5)

我也遇到了这个问题,原因是我想将组件动态加载到的位置在ng-if内部(如果最初是隐藏的)。

<div *ngIf="items">
   <ng-template appInputHost></ng-template>
</div>

@ViewChild(InputHostDirective, { static: true }) inputHost: InputHostDirective;

将ng-template移到ng-if外部即可解决问题。

答案 3 :(得分:2)

在Angular 8中,我的解决方法是:

@ViewChild('dynamicComponent', {static: true, read: ViewContainerRef}) container: ViewContainerRef;

答案 4 :(得分:0)

请注意,如果指令选择器(在本例中为dynamicComponent)位于:

  1. 组件的第一个元素

  2. 具有* ngIf条件的父元素

因此,我将其放置在html&load组件的非root标记中,仅在条件匹配时将其放置在viewContainerRef中,以避免出现这种情况。

答案 5 :(得分:0)

问题还可能是viewRef(在此示例中为dynamicComponent)的选择器与使用componentFactoryResolver的组件模板中指定的选择器不匹配。

答案 6 :(得分:0)

当指令未构造时,您会看到此错误。您可以在指令的构造函数上设置一个断点,并检查该断点是否命中。如果不是,则表示您没有正确加载指令。然后,您可以检查正在加载指令的组件是否正确将指令添加到模板中。

答案 7 :(得分:0)

在我的情况下,它是Angular 9,指令的选择器在*ngIf内部。我使用的解决方案是:

@ViewChild(ExampleDirective, {static: false}) exampleDirectiveHost: ExampleDirective;

由于此处Angular documentation定义的原因,标记static为假

我做的另一件事是使用

ngAfterViewInit(){
   const viewContainerRef = this.exampleDirectiveHost.viewContainerRef;;
}

答案 8 :(得分:0)

模板 HTML 文件:

<ng-template #containerToHostDynamicallyInjectedComponents"></ng-template>

TS 文件

私有组件引用:ComponentRef = null;

@ViewChild('containerToHostDynamicallyInjectedComponents', {read: ViewContainerRef}) hostContainer: ViewContainerRef;

constructor(private componentFactoryResolver:ComponentFactoryResolver) {}


ngOnInit() {

 const componentFactory = 
    this.componentFactoryResolver.resolveComponentFactory(<COMPONENT_NAME_TO_CREATE>);
    this.hostContainer.clear(); // CLEAR ANY INJECTED COMPONENT IF EXISTED.
    this.componentRef = this.hostContainer.createComponent(componentFactory);

}

```
  • this.componentRef: => 存储动态创建组件的引用以访问组件公共属性和方法,甚至订阅事件发射器

访问组件的属性和使用方法:

 this.componentRef.instance.<PROPERTY_NAME>
 this.componentRef.instance.<METHOD_NAME>();

您甚至可以订阅@Output EVENT EMITTERS

this.componentRef.instance.<OUTPUT_PROPERTY_NAME>
.pipe(
  take(1)
)
.subscribe(response => console.log(response));