I want to dynamically create template. This should be used to build a 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 message:
ComponentResolver
is deprecated for dynamic compilation. UseComponentFactoryResolver
together with@NgModule/@Component.entryComponents
or ANALYZE_FOR_ENTRY_COMPONENTS provider instead. For runtime compile only, you can also useCompiler.compileComponentSync/Async
.
I found this (offical angular2) document
Angular 2 Synchronous Dynamic Component Creation
And understand that I can use either
- Kind of dynamic
ngIf
withComponentFactoryResolver
. If I will pass known components into hosting one 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
<form>
<string-editor
[propertyName]="'code'"
[entity]="entity"
></string-editor>
<string-editor
[propertyName]="'description'"
[entity]="entity"
></string-editor>
...
and in another case this one (string-editor
is replaced with text-editor
)
<form>
<text-editor
[propertyName]="'code'"
[entity]="entity"
></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, 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 solution with the Compiler
AOT and JitCompiler (former RuntimeCompiler)
Would you like to use this features with AOT (ahead of time compilation)? Are you getting:
Error: Error encountered resolving symbol values statically. Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function (position 65:17 in the original .ts file), resolving symbol COMPILER_PROVIDERS in .../node_modules/@angular/compiler/src/compiler.d.ts,
Please, leave your comment, vote here:
EDIT (26/08/2017): The solution below works well with Angular2 and 4. I've updated it to contain a template variable and click handler and tested it with Angular 4.3.
For Angular4, ngComponentOutlet as described in Ophir's answer is a much better solution. But right now it does not support inputs & outputs yet. If [this PR](https://github.com/angular/angular/pull/15362] is accepted, it would be possible through the component instance returned by the create event.
ng-dynamic-component may be the best and simplest solution altogether, but I haven't tested that yet.
@Long Field's answer is spot on! Here's another (synchronous) example:
Live at http://plnkr.co/edit/fdP9Oc.
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
Besides that it was not possible to use
<dynamic-detail>
inside one of the parts being string-editor or text-editor.To enable that you'll need to change
parts.module.ts
anddynamic.module.ts
Inside
parts.module.ts
You'll need to addDynamicDetail
in theDYNAMIC_DIRECTIVES
Also in the
dynamic.module.ts
you'd have to remove the dynamicDetail as they are now part of the partsA 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.
Then use the
_compiler
to compile, then templateUrls are enabled as well.Hope this helps someone else!
Best regards Morten
This is the example of dynamic Form controls generated from server.
https://stackblitz.com/edit/angular-t3mmg6
This example is dynamic Form controls is in add component (This is where you can get the Formcontrols from the server). If you see addcomponent method you can see the Forms Controls. In this example I am not using angular material,but It works (I am using @ work). This is target to angular 6, but works in all previous version.
Need to add JITComplierFactory for AngularVersion 5 and above.
Thanks
Vijay
I must have arrived at the party late, none of the solutions here seemed helpful to me - too messy and felt like too much of a workaround.
What I ended up doing is using
Angular 4.0.0-beta.6
's ngComponentOutlet.This gave me the shortest, simplest solution all written in the dynamic component's file.
my-component
- the component in which a dynamic component is renderingDynamicComponent
- the component to be dynamically built and it is rendering inside my-componentDon't forget to upgrade all the angular libraries to ^Angular 4.0.0
Hope this helps, good luck!
UPDATE
Also works for angular 5.
Building on top of the answer by Ophir Stern, here is a variant which works with AoT in Angular 4. The only issue I have is I cant inject any services into the DynamicComponent, but I can live with that.
note: I haven't tested with Angular 5.
Hope this helps.
Cheers!