3

To allow customer customization, I need a way to load component dynamically using a string, taken from backend.

I see this usefull guide: https://medium.com/angular-in-depth/loading-components-dynamically-in-angular-cd13b9fdb715

but, as other tutorial like the official one, they always assume you already know classnames.

Look at this code from the tutorial:

async loadComponent(vcr: ViewContainerRef, isLoggedIn: boolean) {
    const { GuestCardComponent } = await import('./guest-card/guest-card.component');
    const { UserCardComponent } = await import('./user-card/user-card.component');
    ...

The string inside import is not a problem but the definition of class is.

I need a placeholder in my template for loading a component I know I have in the FileSystem but I don't know its name.

Something like this:

From backend i get:

var dynamic_loading_component = { "classname" : "AdidasCardComponent" , "path" : "/components/adidas.component" }

then I would like to use like this:

const { dynamic_loading_component["classname"] } = await import(dynamic_loading_component["path"]);

vcr.clear();
let component : any = dynamic_loading_component["classname"];
   
return vcr.createComponent(this.cfr.resolveComponentFactory(component))

Some sort of Reflection.

Is it possible?

4
  • 1
    Does this answer your question? Angular 2: Load Component Based on service response Commented Oct 5, 2020 at 8:52
  • Im afraid not because in that example all your possible component are always pre-know as this rows: import {Widget1Component} from '../widget/widget1.component'; import {Widget2Component} from '../widget/widget2.component'; Commented Oct 5, 2020 at 10:01
  • Does this answer your question? How to instantiate a Class from a String in JavaScript Commented Oct 5, 2020 at 10:24
  • I already come to eval but when I try to eval this: const { ExampleComponent } = await import('../pages/example/example.component'); i got this exception: Uncaught (in promise): SyntaxError: await is only valid in async function Commented Oct 5, 2020 at 10:26

1 Answer 1

3

I finally found a way merging some other posts. Its the best I could get.

In the page where you have to dynamic load component, have this:

@ViewChild(PlaceHolderDirective, { static: true })
placeholderHost: PlaceHolderDirective;

...

ngAfterViewInit() 
{
  const viewContainerRef  = this.placeholderHost.viewContainerRef;
  var component_data = { "classname" : "ExampleComponent" }; //this is an example
  this._componentLoader.loadComponent(viewContainerRef, {} );
}

PlaceHolderDirective is:

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

@Directive({ selector: '[component-placeholder]' })
export class PlaceHolderDirective {
  constructor(public viewContainerRef: ViewContainerRef) {}
}

Now, create a Service for loading component dynamically:

import { Injectable,ComponentFactoryResolver, ViewContainerRef, NgModuleFactoryLoader, Injector, Type } from '@angular/core';

@Injectable({ providedIn: 'root' })

export class ComponentLoaderService 
{
  constructor(
    private cfr                   : ComponentFactoryResolver) 
  {
    //constructor
  }

  async loadComponent(vcr: ViewContainerRef, component_data = {} ) 
  {
    vcr.clear();
    const factories     = this.cfr['ngModule']['instance']['__proto__']['constructor']['__annotations__'][0]['declarations'];
    var factoryClass    = <Type<any>>factories.find((x: any) => x.name === component_data["classname"] );
    const factory       = this.cfr.resolveComponentFactory(factoryClass);
    return vcr.createComponent(factory);
  }
}

You still have to register your component in app.module but its the only section you need to write.

Sign up to request clarification or add additional context in comments.

1 Comment

Indeed this post use same solution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.