Ravi Syaniya
Ravi Syaniya

Reputation: 5

How can I dynamically render a component with complex dependencies injected into its constructor?

I am trying to dynamically load a component into a ViewContainerRef, and the component's constructor depends on multiple services (e.g., HttpClient, a custom service, etc.). However, I get an error related to missing providers. Here's what I have tried so far:

Injecting Injector and using it with createComponent. Manually providing dependencies in the module where the component is declared.

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { LoggingService } from './logging.service';

@Component({
    selector: 'app-dynamic',
    template: `<p>Dynamic Component Loaded!</p>`,
})
export class DynamicComponent {
    constructor(private http: HttpClient, private loggingService: LoggingService) {
        console.log('DynamicComponent initialized with HttpClient and LoggingService');
    }
}

import {
    Component,
    ComponentRef,
    Injector,
    ViewChild,
    ViewContainerRef,
} from '@angular/core';
import { DynamicComponent } from './dynamic.component';

@Component({
    selector: 'app-root',
    template: `<button (click)="loadComponent()">Load Dynamic Component</button>
               <ng-container #container></ng-container>`,
})
export class AppComponent {
    @ViewChild('container', { read: ViewContainerRef, static: true })
    container!: ViewContainerRef;

    constructor(private injector: Injector) {}

    loadComponent() {
        const componentRef: ComponentRef<DynamicComponent> = this.container.createComponent(DynamicComponent, {
            injector: this.injector, // Provide the injector to resolve dependencies
        });

        const instance = componentRef.instance;
        console.log('Dynamic component instance:', instance);
    }
}

What I Am Looking For:

Upvotes: 0

Views: 44

Answers (1)

Ahmed Elhakim
Ahmed Elhakim

Reputation: 184

Regards the Error you need to provide HttpClient if you use standalone then you need in app.config.ts to add this

export const appConfig: ApplicationConfig = {
  providers: [
    ...
    provideHttpClient(),
  ],
};

moduel base:

@NgModule({
  imports: [
    BrowserModule,
    // import HttpClientModule after BrowserModule.
    HttpClientModule,
  ],
  declarations: [
    AppComponent,
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {}

Bonus Question:

You can use Injector.create({...}) like this:

@Component({
  selector: 'app-root',
  template: `<button (click)="loadComponent()">Load Dynamic Component</button>
    <ng-container #container></ng-container>`,
  standalone: true,
  imports: [CommonModule],
})
export class AppComponent {
  @ViewChild('container', { read: ViewContainerRef, static: true })
  container!: ViewContainerRef;

  constructor(private injector: Injector) {}

  loadComponent() {
    const componentRef: ComponentRef<DynamicComponent> =
      this.container.createComponent(DynamicComponent, {
        injector: Injector.create({
          providers: [
            {
              provide: HttpClient,
              useValue: { get: () => of('Custom Http Client') },
            },
          ],
          parent: this.injector,
        }),
      });

    const instance = componentRef.instance;
    console.log('Dynamic component instance:', instance);
  }
}

@Component({
  selector: 'app-dynamic',
  template: `<p>Dynamic Component Loaded!</p>
    {{ this.http.get('') | async }} `,
  standalone: true,
  imports: [CommonModule],
})
export class DynamicComponent {
  constructor(public http: HttpClient) {
    console.log(
      'DynamicComponent initialized with HttpClient and LoggingService'
    );
  }
}

enter image description here

Upvotes: 0

Related Questions