snippettypescriptangularCriticalCanonical
How can I use/create dynamic template to compile dynamic Component with Angular 2.0?
Viewed 0 times
angularwithhowcompilecomponentdynamicusetemplatecancreate
Problem
I want to dynamically create a template. This should be used to build a
Until RC4 I was using
I found this document (Angular 2 Synchronous Dynamic Component Creation)
And understand that I can use either
But the question is how to use that
For example. I want to create (based on some configuration conditions) this kind of template for one kind of settings
and in another case this one (
And so on (different number/date/reference
The template is changing, so I cannot use
ComponentType at runtime and place (even replace) it somewhere inside of the hosting Component. Until RC4 I was using
ComponentResolver, but with RC5 I get the following message:ComponentResolver is deprecated for dynamic compilation.
Use ComponentFactoryResolver together with @NgModule/@Component.entryComponents or ANALYZE_FOR_ENTRY_COMPONENTS provider instead.
For runtime compile only, you can also use Compiler.compileComponentSync/Async.
I found this document (Angular 2 Synchronous Dynamic Component Creation)
And understand that I can use either
- Kind of dynamic
ngIfwithComponentFactoryResolver. If I pass known components inside of@Component({entryComponents: [comp1, comp2], ...})- I can use.resolveComponentFactory(componentToRender);
- Real runtime compilation, with
Compiler...
But the question is how to use that
Compiler? The note above says that I should call: Compiler.compileComponentSync/Async - so how? For example. I want to create (based on some configuration conditions) this kind of template for one kind of settings
...
and in another case this one (
string-editor is replaced with text-editor)
...
And so on (different number/date/reference
editors by property types, skipped some properties for some users...). i.e. this is an example, the real configuration could generate much more different and complex templates.The template is changing, so I cannot use
ComponentFactoryResolver and pass existing ones... I need a solution with the Compiler.Solution
EDIT - related to 2.3.0 (2016-12-07)
NOTE: to get solution for previous version, check the history of this post
Similar topic is discussed here Equivalent of $compile in Angular 2. We need to use
In a Nutshell
There is a working plunker/example (dynamic template, dynamic component type, dynamic module,
The principal is:
1) create Template
2) find
3) - create
4) - create
5) - compile
6) - return (and cache for later use)
7) use Target and
Here is a code snippet (more of it here) - Our custom Builder is returning just built/cached
This is it - in nutshell it. To get more details.. read below
.
TL&DR
Observe a plunker and come back to read details in case some snippet requires more explanation
.
Detailed explanation - Angular2 RC6++ & runtime components
Below description of this scenario, we will
NgModule
We need an
While I would like to show a very simple example, in this case, I would need three modules (in fact 4 - but I do not count the AppModule). Please, take this rather than a simple snippet as a basis for a really solid dynamic component generator.
There will be one module for all small components, e.g.
Where
The second will be module for our Dynamic stuff handling. It will contain hosting components and some providers.. which will be singletons. Therefor we will publish them standard way - with
Check the usage of the
Finally, we will need an adhoc, runtime module.. but that will be created later, as a part of
The forth module, application module, is the one who keeps declares compiler providers:
Read (do read) much more about NgModule there:
NOTE: to get solution for previous version, check the history of this post
Similar topic is discussed here Equivalent of $compile in Angular 2. We need to use
JitCompiler and NgModule. Read more about NgModule in Angular2 here:- Angular 2 RC5 - NgModules, Lazy Loading and AoT compilation
In a Nutshell
There is a working plunker/example (dynamic template, dynamic component type, dynamic module,
JitCompiler, ... in action)The principal is:
1) create Template
2) find
ComponentFactory in cache - go to 7)3) - create
Component4) - create
Module5) - compile
Module6) - return (and cache for later use)
ComponentFactory7) use Target and
ComponentFactory to create an Instance of dynamic ComponentHere is a code snippet (more of it here) - Our custom Builder is returning just built/cached
ComponentFactory and the view Target placeholder consume to create an instance of the DynamicComponent// here we get a TEMPLATE with dynamic content === TODO
var template = this.templateBuilder.prepareTemplate(this.entity, useTextarea);
// here we get Factory (just compiled or from cache)
this.typeBuilder
.createComponentFactory(template)
.then((factory: ComponentFactory) =>
{
// Target will instantiate and inject component (we'll keep reference to it)
this.componentRef = this
.dynamicComponentTarget
.createComponent(factory);
// let's inject @Inputs to component instance
let component = this.componentRef.instance;
component.entity = this.entity;
//...
});This is it - in nutshell it. To get more details.. read below
.
TL&DR
Observe a plunker and come back to read details in case some snippet requires more explanation
.
Detailed explanation - Angular2 RC6++ & runtime components
Below description of this scenario, we will
- create a module
PartsModule:NgModule(holder of small pieces)
- create another module
DynamicModule:NgModule, which will contain our dynamic component (and referencePartsModuledynamically)
- create dynamic Template (simple approach)
- create new
Componenttype (only if template has changed)
- create new
RuntimeModule:NgModule. This module will contain the previously createdComponenttype
- call
JitCompiler.compileModuleAndAllComponentsAsync(runtimeModule)to getComponentFactory
- create an Instance of the
DynamicComponent- job of the View Target placeholder andComponentFactory
- assign
@Inputsto new instance (switch fromINPUTtoTEXTAREAediting), consume@Outputs
NgModule
We need an
NgModules.While I would like to show a very simple example, in this case, I would need three modules (in fact 4 - but I do not count the AppModule). Please, take this rather than a simple snippet as a basis for a really solid dynamic component generator.
There will be one module for all small components, e.g.
string-editor, text-editor (date-editor, number-editor...)@NgModule({
imports: [
CommonModule,
FormsModule
],
declarations: [
DYNAMIC_DIRECTIVES
],
exports: [
DYNAMIC_DIRECTIVES,
CommonModule,
FormsModule
]
})
export class PartsModule { }Where
DYNAMIC_DIRECTIVES are extensible and are intended to hold all small parts used for our dynamic Component template/type. Check app/parts/parts.module.tsThe second will be module for our Dynamic stuff handling. It will contain hosting components and some providers.. which will be singletons. Therefor we will publish them standard way - with
forRoot()import { DynamicDetail } from './detail.view';
import { DynamicTypeBuilder } from './type.builder';
import { DynamicTemplateBuilder } from './template.builder';
@NgModule({
imports: [ PartsModule ],
declarations: [ DynamicDetail ],
exports: [ DynamicDetail],
})
export class DynamicModule {
static forRoot()
{
return {
ngModule: DynamicModule,
providers: [ // singletons accross the whole app
DynamicTemplateBuilder,
DynamicTypeBuilder
],
};
}
}Check the usage of the
forRoot() in the AppModuleFinally, we will need an adhoc, runtime module.. but that will be created later, as a part of
DynamicTypeBuilder job.The forth module, application module, is the one who keeps declares compiler providers:
...
import { COMPILER_PROVIDERS } from '@angular/compiler';
import { AppComponent } from './app.component';
import { DynamicModule } from './dynamic/dynamic.module';
@NgModule({
imports: [
BrowserModule,
DynamicModule.forRoot() // singletons
],
declarations: [ AppComponent],
providers: [
COMPILER_PROVIDERS // this is an app singleton declaration
],Read (do read) much more about NgModule there:
- Angular 2 RC5 - NgModules, Lazy Loading and AoT com
Code Snippets
// here we get a TEMPLATE with dynamic content === TODO
var template = this.templateBuilder.prepareTemplate(this.entity, useTextarea);
// here we get Factory (just compiled or from cache)
this.typeBuilder
.createComponentFactory(template)
.then((factory: ComponentFactory<IHaveDynamicData>) =>
{
// Target will instantiate and inject component (we'll keep reference to it)
this.componentRef = this
.dynamicComponentTarget
.createComponent(factory);
// let's inject @Inputs to component instance
let component = this.componentRef.instance;
component.entity = this.entity;
//...
});@NgModule({
imports: [
CommonModule,
FormsModule
],
declarations: [
DYNAMIC_DIRECTIVES
],
exports: [
DYNAMIC_DIRECTIVES,
CommonModule,
FormsModule
]
})
export class PartsModule { }import { DynamicDetail } from './detail.view';
import { DynamicTypeBuilder } from './type.builder';
import { DynamicTemplateBuilder } from './template.builder';
@NgModule({
imports: [ PartsModule ],
declarations: [ DynamicDetail ],
exports: [ DynamicDetail],
})
export class DynamicModule {
static forRoot()
{
return {
ngModule: DynamicModule,
providers: [ // singletons accross the whole app
DynamicTemplateBuilder,
DynamicTypeBuilder
],
};
}
}...
import { COMPILER_PROVIDERS } from '@angular/compiler';
import { AppComponent } from './app.component';
import { DynamicModule } from './dynamic/dynamic.module';
@NgModule({
imports: [
BrowserModule,
DynamicModule.forRoot() // singletons
],
declarations: [ AppComponent],
providers: [
COMPILER_PROVIDERS // this is an app singleton declaration
],entity = {
code: "ABC123",
description: "A description of this Entity"
};Context
Stack Overflow Q#38888008, score: 174
Revisions (0)
No revisions yet.