5

I have 10 components in my app, while I call Home route I want to load dynamic components base on Home service response.

Home page component

enter image description here

Code will execute like, Home component - > Call HTTP Service -> returns me list name of array component name [e.g ]

enter image description here -> Now I want to append 2 components in content area

Page will render like enter image description here

Gaëtan Maisse
  • 12,208
  • 9
  • 44
  • 47
Yatin Patel
  • 512
  • 7
  • 17
  • I already done stick component loading by doing this code. https://plnkr.co/edit/AvXNQZrSU28NaM3bzYA2?p=preview – Yatin Patel Feb 26 '17 at 06:10
  • where is the widget1 and widget2 components are physically available? create a partial working model in plunker instead of having the code in `
    ` tag.
    – Aravind Feb 26 '17 at 06:36
  • Similar to http://stackoverflow.com/questions/36325212/angular-2-dynamic-tabs-with-user-click-chosen-components/36325468#36325468 – Günter Zöchbauer Mar 03 '17 at 10:14

1 Answers1

7

Have you seen the doc about dynamic component loading? It shows how you can dynamically insert components into the DOM.

More specifically, there are a few things you need to pay attention to:

1) Define an anchor point where the components will be inserted

You can do that with a template variable (#content):

@Component({
  template: `
    <nav>...</nav>

    <!-- This is where your components will be inserted -->
    <div class="container" #content></div>

    <footer>...</footer>
  `
})
export class MyComponent {
  @ViewChild('content', {read: ViewContainerRef}) content: ViewContainerRef;

  constructor(private componentFactory: ComponentFactoryResolver) { }

  ngAfterViewInit() {
    this.loadComponents();
  }

  loadComponents() {
    // Here, fetch the components from the backend
    // and insert them at the anchor point.
  }
}

2) Get the component CLASSES to insert and add them to the DOM

The problem is that your backend returns component names as strings, but ComponentFactoryResolver expects classes.

You need to map component names to actual classes. You could use a custom object for this:

import {Widget1Component} from '../widget/widget1.component';
import {Widget2Component} from '../widget/widget2.component';
const componentsRegistry = {
  'Widget1Component': Widget1Component
  'Widget2Component': Widget2Component
};

Now the loadComponents() method is easier to write:

loadComponents() {
  // Fetch components to display from the backend.
  const components = [
    { name: 'widget1', componentName: 'Widget1Component' },
    { name: 'widget2', componentName: 'Widget2Component' }
  ];
  // Insert...
  let componentClass, componentFactory;
  for (let c of components) {
    // Get the actual class for the current component.
    componentClass = componentsRegistry[c.componentName];
    // Get a factory for the current component.
    componentFactory = this.componentFactory.resolveComponentFactory(componentClass);
    // Insert the component at the anchor point.
    this.content.createComponent(componentFactory);
  }
}

3) Do not forget to add the dynamic components to entryComponents

Dynamically loaded components have to be added to their NgModule's entryComponents array:

@NgModule({
  // ...
  entryComponents: [Widget1Component, Widget2Component, ...]
  // ...
})
export class AppModule{ }
AngularChef
  • 13,797
  • 8
  • 53
  • 69