Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2: Loading modules dynamically from a given folder

Tags:

app  |-plugins        |-plugin1            |-config.json            |-plugin1.module.ts            |-plugin1.component.ts         |-plugin2            |-config.json            |-plugin2.module.ts            |-plugin2.component.ts 

As you can see above, I have "app/plugins" folder, which contains plugins. Each plugin will contain one "config.json" file which will tell some configuration including -

{    path: "feature1",    moduleFile: "feature1.module",    moduleClassName: "Feature1Module" } 

So what I want is, before application bootstrap it will scan the "app/plugins" folder and load all plugin configurations, and lazily register all module routes. For above example the route will be

{      path: "feature1",      loadChildren: "app/plugins/plugin1/plugin1.module#Plugin1Module" } 

That way, we can drop new plugin into plugin folder and refresh the application, and our newly dropped plugin is up and running.

Anyone knows how can I achieve this?

NOTE: I am on angular2 latest(2.1.0)

like image 782
Jahid Shohel Avatar asked Oct 14 '16 09:10

Jahid Shohel


1 Answers

I'm looking for the same behavior than the one you're describing and I think I've found how to do it, thanks to this github issue : Lazy loading components without Route

Here is the code I've written to do it : plunker here

  • First : dynamic.module.ts, the dynamically loaded module and its component

    import { Component, NgModule } from '@angular/core'  @Component({     selector: 'my-test',     template: `<h1>html template of TestComponent from DynamicModule</h1>` })  export class TestComponent { }  @NgModule({     declarations: [TestComponent],     exports: [TestComponent] })  export class DynamicModule { } 
  • Second : here is the component which dynamically loads module when you give it the module path.

    import { Component,  ViewContainerRef, Compiler, ComponentFactory, ComponentFactoryResolver, ModuleWithComponentFactories, ComponentRef, ReflectiveInjector, SystemJsNgModuleLoader } from '@angular/core';  class ModuleNode {     modulePath: string;     componentName: string; }  @Component({     moduleId: module.id,     selector: 'widgetContainer',     templateUrl: './widgetContainer.component.html' })  export class WidgetContainerComponent {     widgetConfig: string;     module: ModuleNode;     cmpRef: ComponentRef<any>;  constructor(private widgetService: WidgetLoader,     private viewref: ViewContainerRef,     private resolver: ComponentFactoryResolver,     private loader: SystemJsNgModuleLoader,     private compiler: Compiler){}  openWebApp(menu:any) {     this.loader.load(menu.modulePath)  // load the module and its components         .then((modFac) => {             // the missing step, need to use Compiler to resolve the module's embedded components             this.compiler.compileModuleAndAllComponentsAsync<any>(modFac.moduleType)                  .then((factory: ModuleWithComponentFactories<any>) => {                     return factory.componentFactories.find(x => x.componentType.name === menu.componentName);                 })                 .then(cmpFactory => {                      // need to instantiate the Module so we can use it as the provider for the new component                     let modRef = modFac.create(this.viewref.parentInjector);                     this.cmpRef = this.viewref.createComponent(cmpFactory, 0, modRef.injector);                     // done, now Module and main Component are known to NG2                  });         }); }  ngOnDestroy() {     if (this.cmpRef) {         this.cmpRef.destroy();     } } 

    }

What do you think about that? Does it help? Thanks a lot for your feedback.

like image 51
Mawycezil Avatar answered Oct 13 '22 13:10

Mawycezil