Richard Houltz
Richard Houltz

Reputation: 1962

Angular2 - Change template of dynamic component / reload module

I have a dynamic component which receives its template in runtime and is compiled on the fly with the compileModuleAndAllComponentsSync method of Compiler from '@angular/core'.

Here is the code I use to get the componentFactory of the runtime component (please see the Plunker for complete code, all the interesting stuff is in runtime-content.component.ts)

private createComponentFactorySync(compiler: Compiler, metadata: Component): ComponentFactory<any> {
    let decoratedCmp = Component(metadata)(RuntimeComponent);

    @NgModule({ imports: [CommonModule], declarations: [decoratedCmp] })
    class RuntimeComponentModule { }

    let module: ModuleWithComponentFactories<any> = compiler.compileModuleAndAllComponentsSync(RuntimeComponentModule);

    return module.componentFactories.find(f => f.componentType === decoratedCmp);
}

enter image description here

It all works fine and the dynamic template is working fine the first time it is compiled. For my use case however I need to be able to change the template and recompile several times. But the second time I try to compile I get the error

"Type RuntimeComponent is part of the declarations of 2 modules: RuntimeComponentModule and RuntimeComponentModule!"

This of course makes sense since it does compile into another module of the same type. So my idea has been to try to unload the previously created module but cannot find any way to do that.

Anyone have an idea to acheive what I'm trying to do? Maybe by unloading the module or perhaps in another way. I have provided a working plunker to show the problem. Press the 'compile' button which will compile the dynamic template which will work fine (pressing the 'Inc' button increases the value). Pressing compile a second time will raise the error described above and the component stops working.

Plunker

Upvotes: 1

Views: 1677

Answers (2)

No&#233;mi Sala&#252;n
No&#233;mi Sala&#252;n

Reputation: 5036

Another solution would be to declare a new class for each new component and don't re-use the same RuntimeComponent each time.

protected createNewComponent(tmpl: string) {

    @Component({
        selector: `runtime-component-dynamic`,
        template: tmpl
    })
    class RuntimeComponent {
        name: string = 'Tim Jelly';
        value: number = 42;

        incValue() {
            this.value++;
        }
    }

    return RuntimeComponent;
}

See Plunker

Upvotes: 0

yurzui
yurzui

Reputation: 214295

I would solve your problem by using compiler.clearCacheFor method:

compiler.clearCacheFor(decoratedCmp);

Plunker Example

See also

Upvotes: 1

Related Questions