You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 10:10:06