I want to dynamically create a template. This should be used to build a ComponentType
at runtime and place (even replace) it somewhere inside of the ho
I want to add a few details on top of this very excellent post by Radim.
I took this solution and worked on it for a bit and quickly ran into some limitations. I'll just outline those and then give the solution to that as well.
I made another question based on this post, on how to achieve these limitations, which can be found here:
recursive dynamic template compilation in angular2
I’ll just outline the answers to these limitations, should you run into the same issue as I, as that make the solution quite more flexible. It would be awesome to have the initial plunker updated with that as well.
To enable nesting dynamic-detail inside each other, You'll need to add DynamicModule.forRoot() in the import statement in the type.builder.ts
protected createComponentModule (componentType: any) {
@NgModule({
imports: [
PartsModule,
DynamicModule.forRoot() //this line here
],
declarations: [
componentType
],
})
class RuntimeComponentModule
{
}
// a module for just this Type
return RuntimeComponentModule;
}
Besides that it was not possible to use
inside one of the parts being string-editor or text-editor.
To enable that you'll need to change parts.module.ts
and dynamic.module.ts
Inside parts.module.ts
You'll need to add DynamicDetail
in the DYNAMIC_DIRECTIVES
export const DYNAMIC_DIRECTIVES = [
forwardRef(() => StringEditor),
forwardRef(() => TextEditor),
DynamicDetail
];
Also in the dynamic.module.ts
you'd have to remove the dynamicDetail as they are now part of the parts
@NgModule({
imports: [ PartsModule ],
exports: [ PartsModule],
})
A working modified plunker can be found here: http://plnkr.co/edit/UYnQHF?p=preview (I didn’t solve this issue, I’m just the messenger :-D)
Finally it was not possible to use templateurls in the parts created on the dynamic components. A solution (or workaround. I’m not sure whether it’s an angular bug or wrong use of the framework) was to create a compiler in the constructor instead of injecting it.
private _compiler;
constructor(protected compiler: RuntimeCompiler) {
const compilerFactory : CompilerFactory =
platformBrowserDynamic().injector.get(CompilerFactory);
this._compiler = compilerFactory.createCompiler([]);
}
Then use the _compiler
to compile, then templateUrls are enabled as well.
return new Promise((resolve) => {
this._compiler
.compileModuleAndAllComponentsAsync(module)
.then((moduleWithFactories) =>
{
let _ = window["_"];
factory = _.find(moduleWithFactories.componentFactories, { componentType: type });
this._cacheOfFactories[template] = factory;
resolve(factory);
});
});
Hope this helps someone else!
Best regards Morten