How can I use/create dynamic template to compile dynamic Component with Angular 2.0?

后端 未结 15 1871
忘掉有多难
忘掉有多难 2020-11-21 05:14

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

相关标签:
15条回答
  • 2020-11-21 05:38

    I have a simple example to show how to do angular 2 rc6 dynamic component.

    Say, you have a dynamic html template = template1 and want to dynamic load, firstly wrap into component

    @Component({template: template1})
    class DynamicComponent {}
    

    here template1 as html, may be contains ng2 component

    From rc6, have to have @NgModule wrap this component. @NgModule, just like module in anglarJS 1, it decouple different part of ng2 application, so:

    @Component({
      template: template1,
    
    })
    class DynamicComponent {
    
    }
    @NgModule({
      imports: [BrowserModule,RouterModule],
      declarations: [DynamicComponent]
    })
    class DynamicModule { }
    

    (Here import RouterModule as in my example there is some route components in my html as you can see later on)

    Now you can compile DynamicModule as: this.compiler.compileModuleAndAllComponentsAsync(DynamicModule).then( factory => factory.componentFactories.find(x => x.componentType === DynamicComponent))

    And we need put above in app.moudule.ts to load it, please see my app.moudle.ts. For more and full details check: https://github.com/Longfld/DynamicalRouter/blob/master/app/MyRouterLink.ts and app.moudle.ts

    and see demo: http://plnkr.co/edit/1fdAYP5PAbiHdJfTKgWo?p=preview

    0 讨论(0)
  • 2020-11-21 05:41

    I myself am trying to see how can I update RC4 to RC5 and thus I stumbled upon this entry and new approach to dynamic component creation still holds a bit of mystery to me, so I wont suggest anything on component factory resolver.

    But, what I can suggest is a bit clearer approach to component creation on this scenario - just use switch in template that would create string editor or text editor according to some condition, like this:

    <form [ngSwitch]="useTextarea">
        <string-editor *ngSwitchCase="false" propertyName="'code'" 
                     [entity]="entity"></string-editor>
        <text-editor *ngSwitchCase="true" propertyName="'code'" 
                     [entity]="entity"></text-editor>
    </form>
    

    And by the way, "[" in [prop] expression have a meaning, this indicates one way data binding, hence you can and even should omit those in case if you know that you do not need to bind property to variable.

    0 讨论(0)
  • 2020-11-21 05:43

    If all you need as a way to parse a dynamic string and load components by their selectors, you may also find the ngx-dynamic-hooks library useful. I initially created this as part of a personal project but didn't see anything like it around, so I polished it up a bit and made it public.

    Some tidbids:

    • You can load any components into a dynamic string by their selector (or any other pattern of your choice!)
    • Inputs and outputs can be se just like in a normal template
    • Components can be nested without restrictions
    • You can pass live data from the parent component into the dynamically loaded components (and even use it to bind inputs/outputs)
    • You can control which components can load in each outlet and even which inputs/outputs you can give them
    • The library uses Angular's built-in DOMSanitizer to be safe to use even with potentially unsafe input.

    Notably, it does not rely on a runtime-compiler like some of the other responses here. Because of that, you can't use template syntax. On the flipside, this means it works in both JiT and AoT-modes as well as both Ivy and the old template engine, as well as being much more secure to use in general.

    See it in action in this Stackblitz.

    0 讨论(0)
  • 2020-11-21 05:45

    Solved this in Angular 2 Final version simply by using the dynamicComponent directive from ng-dynamic.

    Usage:

    <div *dynamicComponent="template; context: {text: text};"></div>
    

    Where template is your dynamic template and context can be set to any dynamic datamodel that you want your template to bind to.

    0 讨论(0)
  • 2020-11-21 05:48

    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

    0 讨论(0)
  • 2020-11-21 05:49

    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.

    • First of all I was unable to render dynamic-detail inside a dynamic-detail (basically nest dynamic UIs inside each other).
    • The next issue was that I wanted to render a dynamic-detail inside one of the parts that was made available in the solution. That was not possible with the initial solution either.
    • Lastly it was not possible to use template URLs on the dynamic parts like string-editor.

    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 <dynamic-detail> 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

    0 讨论(0)
提交回复
热议问题