Angular 18主组件调用动态加载器时出现loadComponent未定义错误
问题描述
我定义了Textbox、Autocomplete、Button等组件,希望在另一个组件中基于名称动态加载它们,编写完代码后运行出现报错:
ERROR TypeError: Cannot read properties of undefined (reading 'loadComponent') at _Form001Component.ngOnInit
已实现的代码
1. DynamicHostDirective 指令
import { Directive, ViewContainerRef } from '@angular/core'; @Directive({ selector: '[appDynamicHost]', standalone: true }) export class DynamicHostDirective { constructor(public viewContainerRef: ViewContainerRef) { } }
2. DynamicComponentService 服务
import { Injectable, Type } from '@angular/core'; import { PngAutoCompleteComponent } from '@components/components/png-auto-complete/png-auto-complete.component'; import { PngButtonComponent } from '@components/components/png-button/png-button.component'; import { PngTextboxComponent } from '@components/components/png-textbox/png-textbox.component'; @Injectable({ providedIn: 'root' }) export class DynamicComponentService { constructor() { } private components: { [key: string]: Type<any> } = { 'pngTextbox': PngTextboxComponent, 'pngButton': PngButtonComponent, 'pngAutoComplete':PngAutoCompleteComponent }; getComponent(name: string): Type<any> | null { return this.components[name] || null; } }
3. DynamicLoaderComponent 动态加载器
.ts 文件
import { Component, ComponentRef, ViewChild } from '@angular/core'; import { DynamicComponentService } from '@services/dynamic-component.service'; import { DynamicHostDirective } from 'src/app/directives/dynamic-host.directive'; @Component({ selector: 'app-dynamic-loader', standalone: true, imports: [], templateUrl: './dynamic-loader.component.html', styleUrl: './dynamic-loader.component.scss' }) export class DynamicLoaderComponent { @ViewChild(DynamicHostDirective, { static: true }) dynamicHost!: DynamicHostDirective; private componentRef!: ComponentRef<any>; constructor(private dynamicService: DynamicComponentService) { } loadComponent(componentName: string, data: any) { const componentType = this.dynamicService.getComponent(componentName); if (!componentType) { console.error(`Component "${componentName}" not found!`); return; } const viewContainerRef = this.dynamicHost.viewContainerRef; viewContainerRef.clear(); this.componentRef = viewContainerRef.createComponent(componentType); if (this.componentRef.instance) { this.componentRef.instance.data = data; } } getComponentData() { if (this.componentRef && this.componentRef.instance) { return this.componentRef.instance.data; } return null; } ngOnInit() {} }
.html 文件
<ng-template #dynamicHost></ng-template>
4. 主组件 Form001Component
.ts 文件
import { Component, OnInit, ViewChild } from '@angular/core'; import { DynamicLoaderComponent } from '@components/components/dynamic-loader/dynamic-loader.component'; @Component({ selector: 'app-form-001', standalone: true, imports: [DynamicLoaderComponent], templateUrl: './form-001.component.html', styleUrl: './form-001.component.scss' }) export class Form001Component implements OnInit{ @ViewChild('dynamicLoaderx') dynamicLoader!: DynamicLoaderComponent; // constructor (private dynamicLoader: DynamicLoaderComponent) {} ngOnInit(): void { this.dynamicLoader.loadComponent('pngTextbox', { invoiceNumber: '12345', date: '1402/12/01' }); } }
.html 文件
<app-dynamic-loader #dynamicLoaderx></app-dynamic-loader>
问题原因及解决方案
原因1:@ViewChild 未配置 static: true
Angular中@ViewChild默认static为false,意味着组件实例会在变更检测后才被查询到。而ngOnInit执行时视图还未完全渲染,dynamicLoader还未被赋值,调用loadComponent就会报错。
解决方案:修改Form001Component中的@ViewChild配置:
@ViewChild('dynamicLoaderx', { static: true }) dynamicLoader!: DynamicLoaderComponent;
原因2:DynamicLoaderComponent模板未正确关联指令
模板中使用的#dynamicHost是模板变量,但指令的选择器是[appDynamicHost],导致dynamicHost实例无法被获取,后续loadComponent执行也会出错。
解决方案:修改DynamicLoaderComponent的.html文件:
<ng-template appDynamicHost></ng-template>
原因3:DynamicLoaderComponent未导入指令
因为DynamicLoaderComponent是独立组件,需要显式导入DynamicHostDirective才能使用。
解决方案:修改DynamicLoaderComponent的imports数组:
@Component({ selector: 'app-dynamic-loader', standalone: true, imports: [DynamicHostDirective], // 添加此行 templateUrl: './dynamic-loader.component.html', styleUrl: './dynamic-loader.component.scss' })
内容的提问来源于stack exchange,提问作者Blue Moon
相关产品推荐
相关产品推荐

