Angular2 – Carica dynamicmente il componente dal modulo

nella mia app angular ho il seguente:

export class MyComponent { subcompPath = "path-to-subcomp#SubcompClassName"; @ViewChild("placeholder", { read: ViewComponentRef }) placeholderRef: ViewComponentRef; /* Constructor where Compiler, ComponentFactoryResolver are injected */ loadSubcomponent() { let [path, componentName] = this.subcompPath.split("#"); (window).System.import(path) .then((module: any) => module[componentName]) .then((type: any) => { return this._compiler.compileComponentAsync(type) }) .then((factory: any) => { let componentRef = this.placeholderRef.createComponent(factory, 0); }); } } 

Il mio sottocomponente dichiara fornitori e cose, direttive e pipe.

E ora RC6 è pronto a rompere tutto ancora. I componenti non possono dichiarare direttive e pipe, ma devono essere nel modulo in cui è dichiarato il componente. Quindi devo caricare con SystemJS non il componente stesso ma il modulo. Ok, e quindi dovrei usare

 return this._compiler.compileModuleAndAllComponentsAsync(type) 

Bene, ma come faccio a ottenere un riferimento alla fabbrica di questo specifico componente? Quella fabbrica è tutto ciò di cui ho bisogno, il placeholderRef lo vuole nel suo metodo createComponent, giusto?

Ho provato a scavare nel codice sorgente angular2 di github ma è piuttosto vasto, dovrei provare da VS Code o qualcosa del genere, con intellisense, ma sono pigro … e dovrei leggere questa roba dalla documentazione, che è piuttosto scialbo in angular.io per questo particolare argomento, che è il caricamento lazy di componenti e moduli SENZA il router.

Qualsiasi aiuto è apprezzato, penso che la soluzione sia semplice da applicare ma difficile da trovare senza documentazione ufficiale.

Sulla base della risposta di yurzui, sono giunto al seguente codice:

 export class MyComponent { subcompPath = "path-to-subcompMODULE#SubcompClassName"; @ViewChild("placeholder", { read: ViewComponentRef }) placeholderRef: ViewComponentRef; /* Constructor where Compiler, ComponentFactoryResolver are injected */ loadSubcomponent() { let [modulePath, componentName] = this.subcompPath.split("#"); (window).System.import(modulePath) .then((module: any) => module["default"]) // Or pass the module class name too .then((type: any) => { return this._compiler.compileModuleAndAllComponentsAsync(type) }) .then((moduleWithFactories: ModuleWithComponentFactories) => { const factory = moduleWithFactories.componentFactories.find(x => x.componentType.name === componentName); // Crucial: componentType.name, not componentType!! let componentRef = this.placeholderRef.createComponent(factory, 0); }); } } 

Aggiornare:

Se si desidera utilizzarlo insieme alla compilazione aot, è necessario fornire manualmente il compilatore

 export function createJitCompiler () { return new JitCompilerFactory([{useDebug: false, useJit: true}]).createCompiler(); } ... providers: [ { provide: Compiler, useFactory: createJitCompiler} ], 

Esempio

Vecchia versione

Potrebbe aiutarti:

 this.compiler.compileModuleAndAllComponentsAsync(DynamicModule) .then(({moduleFactory, componentFactories}) => { const compFactory = componentFactories .find(x => x.componentType === DynamicComponent); const cmpRef = this.placeholderRef.createComponent(compFactory, 0); 

Guarda anche

  • connessi rispondono con un esempio
  • Come utilizzare la variabile per definire templateUrl in Angular2
  • codice di esempio dal codice sorgente angular2