a similar "bug" was raised in the issue of Angular :
https://github.com/angular/angular/issues/11015
If you follow my snippet, you can use templateUrl but only for "container", not for the "widget" :
import {
Component,
ComponentFactoryResolver,
ViewContainerRef,
ViewChild,
OnInit,
Compiler
} from '@angular/core';
import {RuntimeCompiler} from "@angular/compiler";
import {EmptyModule} from "./empty.module";
export class MyComponentLoader {
loadComponentConfig(url) {
return fetch(url)
.then(res => res.json())
.then(componentList => Promise.all(
componentList.map(config => this.loadComponent(config))
)
);
}
loadComponent(configObject) {
return System.import(configObject.path)
.then(componentModule =>
componentModule[configObject.component]
)
}
}
@Component({
moduleId: module.id,
selector: 'ng-smartdesk',
templateUrl: './smartdesk.component.html',
providers: [MyComponentLoader],
})
export class SmartdeskComponent implements OnInit {
@ViewChild('widgets', {read: ViewContainerRef})
container: ViewContainerRef;
constructor(private _loader: MyComponentLoader,
protected _compiler: RuntimeCompiler) {
}
ngOnInit() {
this._loader.loadComponentConfig('/app/config.json')
.then(components => {
if (components) {
Promise.all(components.map(test => this.loadComp(test, null)));
}
}, error => console.log(error));
}
private loadComp(comp: Component, index: number) {
this._compiler
.compileComponentAsync(comp, EmptyModule)
.then(factory => {
this.container.createComponent(factory, index, this.container.injector)
});
}
}
Edit : SOLVED ! with the help of Tobias Bosch, the solution is to create a new instance of a compiler. This is my final code :
import {
Component,
ComponentFactoryResolver,
ViewContainerRef,
ViewChild,
OnInit,
Compiler, CompilerFactory
} from '@angular/core';
import {RuntimeCompiler} from "@angular/compiler";
import {EmptyModule} from "./empty.module";
import {platformBrowserDynamic} from "@angular/platform-browser-dynamic";
export class MyComponentLoader {
loadComponentConfig(url) {
return fetch(url)
.then(res => res.json())
.then(componentList => Promise.all(
componentList.map(config => this.loadComponent(config))
)
);
}
loadComponent(configObject) {
return System.import(configObject.path)
.then(componentModule =>
componentModule[configObject.component]
)
}
}
@Component({
moduleId: module.id,
selector: 'ng-smartdesk',
templateUrl: './smartdesk.component.html',
providers: [MyComponentLoader],
})
export class SmartdeskComponent implements OnInit {
@ViewChild('widgets', {read: ViewContainerRef})
container: ViewContainerRef;
private _compiler;
constructor(private _loader: MyComponentLoader) {
const compilerFactory : CompilerFactory = platformBrowserDynamic().injector.get(CompilerFactory);
this._compiler = compilerFactory.createCompiler([]);
}
ngOnInit() {
this._loader.loadComponentConfig('/app/config.json')
.then(components => {
if (components) {
Promise.all(components.map(test => this.loadComp(test, null)));
}
}, error => console.log(error));
}
private loadComp(comp: Component, index: number) {
this._compiler
.compileComponentAsync(comp, EmptyModule)
.then(factory => {
this.container.createComponent(factory, index, this.container.injector)
});
}
}