2

In my Angular 5 project I need to create one component dynamically after API data is downloaded (I have HTML code inside with Angular markups - I need to compile them after request is done), but I see there is the problem with AOT.

I've tried to use solution from that topic Angular 4 | Template bind through innerHTML, component variables are not accessible (damContentRoot is this case) (and from that How can I use/create dynamic template to compile dynamic Component with Angular 2.0?)

Here is my current code:

import {
    Directive,
    OnChanges,
    Input,
    ComponentRef,
    ViewContainerRef,
    Compiler,
    ModuleWithComponentFactories,
    Component,
    NgModule,
    Type
} from '@angular/core';

import {CommonModule} from '@angular/common';
import { FormsModule, ReactiveFormsModule, NgForm }   from '@angular/forms';
import {JitCompilerFactory} from '@angular/platform-browser-dynamic';





@Directive({selector: '[compile]'})
export class CompileDirective implements OnChanges {
    @Input()compile : string;
    @Input()compileContext : any;

    compRef : ComponentRef < any >;

    constructor(private vcRef : ViewContainerRef, private compiler : Compiler) {}

    ngOnChanges() {
        if (!this.compile) {
            if (this.compRef) {
                this.updateProperties();
                return;
            }
            throw Error('You forgot to provide template');
        }

        this
            .vcRef
            .clear();
        this.compRef = null;

        const component = this.createDynamicComponent(this.compile);
        const module = this.createDynamicModule(component);
        this
            .compiler
            .compileModuleAndAllComponentsAsync(module)
            .then((moduleWithFactories : ModuleWithComponentFactories < any >) => {
                let compFactory = moduleWithFactories
                    .componentFactories
                    .find(x => x.componentType === component);

                this.compRef = this
                    .vcRef
                    .createComponent(compFactory);
                this.updateProperties();
            })
            .catch(error => {
                console.log(error);
            });
    }

    updateProperties() {
        for (var prop in this.compileContext) {
            this.compRef.instance[prop] = this.compileContext[prop];
        }
    }

    private createDynamicComponent(template : string) {
        @Component({selector: 'custom-dynamic-component', template: template})
        class CustomDynamicComponent {}
        return CustomDynamicComponent;
    }

    private createDynamicModule(component : Type < any >) {
        @NgModule({
            // You might need other modules, providers, etc... Note that whatever components
            // you want to be able to render dynamically must be known to this module
            imports: [CommonModule, FormsModule, ReactiveFormsModule],
            declarations: [component],
        })
        class DynamicModule {}
        return DynamicModule;
    }
}

<ng-container *compile="this.pageData.html; context: this"></ng-container>

But I'm getting error : ERROR Error: Runtime compiler is not loaded

I've tried to use JitCompilterFactory also but I'm getting error like there : https://github.com/angular/angular/issues/20639.

Is there any way to to add component at runtime with aot compilation ? Or it's not making any sens to combine it together with JIT?

I've read whole topic about dynamic component loading (https://blog.angularindepth.com/here-is-what-you-need-to-know-about-dynamic-components-in-angular-ac1e96167f9e) and I still can't find solution, always JitCompilerFactory error.

Patryk Panek
  • 405
  • 4
  • 20
  • It's probably possible to do this with a hack but I don't know what the hack is. I will say that if you have a lot of scenarios like this he will keep butting heads with the framework because it does not want anything to be dynamic whatsoever – Aluan Haddad Feb 14 '18 at 14:36
  • 1
    https://stackoverflow.com/a/45506470/7945055 Maybe SystemJS will solve the problem ? – Patryk Panek Feb 14 '18 at 14:37
  • Hi @PatrykPanek, check out my post on dynamic components and reactive forms. In my answer there is a stackblitz example that may help you resolve your issue. https://stackoverflow.com/questions/48753464/angular-how-to-use-reactive-forms-in-a-dynamic-component – Narm Feb 16 '18 at 03:24
  • 1
    @Narm thank You for answer, but in your solution, You'r using `Compiler` library. I think it won't work at Runtime with AOT in Angular 5. – Patryk Panek Feb 16 '18 at 07:10

1 Answers1

0

I have HTML code inside with Angular markups - I need to compile them after request is done

I all you need is a way to load components into dynamic strings based on their selectors, the ngx-dynamic-hooks-library that I wrote might help. I've created it for that exact purpose since I also didn't find any other good solution.

It works with both JiT and Aot modes, as it doesn't rely on a runtime-compiler at all, so you wouldn't have to worry about that. See it working here.

Mvin
  • 385
  • 4
  • 12