最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Problem loading a component when calling it in the main component in Angular 18 - Stack Overflow

programmeradmin2浏览0评论

I have defined several components, including Textbox, Autocomplete, and Button, and I want to use them in another component. My goal is to dynamically load a component in another component based on its name. To achieve this, I wrote the following code:

I created a directive as follows:

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appDynamicHost]',
  standalone: true
})
export class DynamicHostDirective {

  constructor(public viewContainerRef: ViewContainerRef) { }

}

I wrote a service as follows:

import { Injectable, Type } from '@angular/core';
import { PngAutoCompleteComponent } from '@components/components/png-auto-complete/png-auto-completeponent';
import { PngButtonComponent } from '@components/components/png-button/png-buttonponent';
import { PngTextboxComponent } from '@components/components/png-textbox/png-textboxponent';

@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 thisponents[name] || null;
  }
  
}

I implemented a dynamic component loader as follows:

.ts file :

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-loaderponent.html',
  styleUrl: './dynamic-loaderponent.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();
    thisponentRef = viewContainerRef.createComponent(componentType);

    if (thisponentRef.instance) {
      thisponentRef.instance.data = data;
    }
  }

  getComponentData() {
    if (thisponentRef && thisponentRef.instance) {
      return thisponentRef.instance.data;
    }
    return null;
  }

  ngOnInit() {}
}

html file:

<ng-template #dynamicHost></ng-template>

Finally, I called the dynamic component loader in the main component.

.ts file:

import { Component, OnInit, ViewChild } from '@angular/core';
import { DynamicLoaderComponent } from '@components/components/dynamic-loader/dynamic-loaderponent';


@Component({
  selector: 'app-form-001',
  standalone: true,
  imports: [DynamicLoaderComponent],
  templateUrl: './form-001ponent.html',
  styleUrl: './form-001ponent.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' });
  }
}

.hrml file:

<app-dynamic-loader #dynamicLoaderx></app-dynamic-loader>

I am not sure what I did wrong, but I am getting the following error:

ERROR TypeError: Cannot read properties of undefined (reading 'loadComponent')
    at _Form001Component.ngOnInit

I have defined several components, including Textbox, Autocomplete, and Button, and I want to use them in another component. My goal is to dynamically load a component in another component based on its name. To achieve this, I wrote the following code:

I created a directive as follows:

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appDynamicHost]',
  standalone: true
})
export class DynamicHostDirective {

  constructor(public viewContainerRef: ViewContainerRef) { }

}

I wrote a service as follows:

import { Injectable, Type } from '@angular/core';
import { PngAutoCompleteComponent } from '@components/components/png-auto-complete/png-auto-completeponent';
import { PngButtonComponent } from '@components/components/png-button/png-buttonponent';
import { PngTextboxComponent } from '@components/components/png-textbox/png-textboxponent';

@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 thisponents[name] || null;
  }
  
}

I implemented a dynamic component loader as follows:

.ts file :

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-loaderponent.html',
  styleUrl: './dynamic-loaderponent.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();
    thisponentRef = viewContainerRef.createComponent(componentType);

    if (thisponentRef.instance) {
      thisponentRef.instance.data = data;
    }
  }

  getComponentData() {
    if (thisponentRef && thisponentRef.instance) {
      return thisponentRef.instance.data;
    }
    return null;
  }

  ngOnInit() {}
}

html file:

<ng-template #dynamicHost></ng-template>

Finally, I called the dynamic component loader in the main component.

.ts file:

import { Component, OnInit, ViewChild } from '@angular/core';
import { DynamicLoaderComponent } from '@components/components/dynamic-loader/dynamic-loaderponent';


@Component({
  selector: 'app-form-001',
  standalone: true,
  imports: [DynamicLoaderComponent],
  templateUrl: './form-001ponent.html',
  styleUrl: './form-001ponent.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' });
  }
}

.hrml file:

<app-dynamic-loader #dynamicLoaderx></app-dynamic-loader>

I am not sure what I did wrong, but I am getting the following error:

ERROR TypeError: Cannot read properties of undefined (reading 'loadComponent')
    at _Form001Component.ngOnInit
Share Improve this question asked Feb 16 at 18:00 Blue MoonBlue Moon 4491 gold badge7 silver badges23 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

The issue is in the timing. dynamicLoader is defined as ViewChild and because of that is available only after the AfterViewInit lifecycle hook and undefined during OnInit. Just switch ngOnInit to ngAfterViewInit and you should be good to go.

发布评论

评论列表(0)

  1. 暂无评论