Angular 9 使用 viewContainerRef 加载动态组件得到未定义的结果

Angular 9 Load Dynamic components with viewContainerRef gets undefined result

我创建了一个在视图中使用视图的应用程序,我无法将我的代码移动到库中,然后共享代码。

我的主页使用带有 loadChildren() 的路由,然后实际加载要查看的组件。我的页面都共享一个通用的导航组件,该组件通过监视可观察对象提供标题栏、侧面菜单、自动隐藏、调整大小等。

因此,我的路由的主要路径是 NavigationComponent,它是简单的 Angular Material 导航示意图。然后它有一个 router-outlet,然后将显示我的目标组件。

我的主要页面是 Material 仪表板示意图。这些显示卡中包含信息并路由到标准 URL 以加载实际组件。

例如,我的主页有导航,然后是一系列卡片来显示不同的数据(关于网站、活动、新闻等)

const routes:Routes = [
    { path: '', component: NavigationCommonComponent,
        children: [
            { path: '', component: HomeComponent },
            { path: 'aboutus', component: AboutComponent },
            { path: 'events', component: EventsComponent },
            { path: 'news', component: NewsComponent },
        ]
    }
];

上面的基本路由可以提供一些信息。当这些只是卡片时,一切正常。我已经把卡片搬进了图书馆,数据可以显示在卡片上了。我现在要做的,实际上是在卡片数据中显示组件的内容。

例如,如果卡是硬编码的,您将使用

<mat-card>
    <appEvents></AppEvents>
</mat-card>

这将使用 EventsController 来显示卡片中的任何内容。硬编码,这有效。我现在要做的是使用 Angular 9 个文档中相同的 viewComponentRef 示例,以便动态加载这些卡片。

例如,我现在有一个数据数组,其中的组件 (Type) 作为要查看的项目。我有一个卡片组件

我使用了示例中的 AdService:

@Injectable()
export class AdService {
    public getAds() {
        return [
            new AdItem(HeroJobAdComponent, {name: 'Bombasto', bio: 'Brave as they come'}),
            new AdItem(HeroJobAdComponent, {name: 'Dr IQ', bio: 'Smart as they come'}),

        ];
    }
}

HeroJobAdComponent

@Component({
template: `
    <div class="job-ad">
    <h4>{{data.headline}}</h4>

    {{data.body}}
    </div>
`
})
export class HeroJobAdComponent implements AdComponent {
@Input() public data:any;

}

和提供的指令。

@Directive({
selector: '[appAdHost]',
})
export class AdDirective {
constructor(public viewContainerRef:ViewContainerRef) { }
}

一切似乎都是正确的,除了代码是 运行,来自 ViewChild 的 viewContainerRef:

@ViewChild(AdDirective, {static: true, read: ViewContainerRef}) public adHost:AdDirective;

const viewContainerRef = this.adHost.viewContainerRef; 行中似乎为空。 adHost 未定义。

public loadComponent() {
    this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;
    const adItem = this.ads[this.currentAdIndex];

    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);

    const viewContainerRef = this.adHost.viewContainerRef;
    viewContainerRef.clear();

    const componentRef = viewContainerRef.createComponent(componentFactory);
    (componentRef.instance as AdComponent).data = adItem.data;
}

我认为这与组件的级别有关,我将 grid/card 列表(material 仪表板示意图)作为导航组件的 child。我不知道如何让这个元素不被定义。

删除 read: ViewContainerRef 属性。