3

I'm trying to load a component dynamically in my Angular2 app. By dynamically I don't just mean to insert into the DOM a component that is missing from the parent component's template; I mean to download from the server another component, because the User might not ever need it, and then insert it into the DOM. So I followed this to understand how to load the component with Systemjs and now I see that, in RC4, we need to use this and ComponentResolver to inject things into the DOM.

So here is my code for the module-wrapper component that should put things together:

export class ModuleWrapperComponent implements OnInit {
    @ViewChild("module", { read: ViewContainerRef }) target: ViewContainerRef;
    @Input() isOpen: boolean;
    @Input() moduleId: number;
    type: string = null;
    moduleRef: ComponentRef<any> = null;

    private isViewInitialized: boolean = false;

    constructor(private resolver: ComponentResolver) { }

    private _loadModule(moduleId: number): Promise<string> {
        if (!!this.type)
            return Promise.resolve(this.type);

        var mod = {
            component: "DashboardComponent",
            path: "/app/modules/dashboard.component"
        };
        return System
            .import(mod.path)
            .then(() => this.type = mod.component);
    }

    updateComponent() {
        if (!this.isViewInitialized)
            return;

        if (!!this.moduleRef)
            this.moduleRef.destroy();

        if (this.isOpen) {
            this._loadModule(this.moduleId)
                .then(type => {
                    this.resolver.resolveComponent(type)
                        .then(factory => {
                            this.moduleRef = this.target.createComponent(factory)
                            // to access the created instance use
                            // this.compRef.instance.someProperty = 'someValue';
                            // this.compRef.instance.someOutput.subscribe(val => doSomething());
                        });
                })
        }
    }

    ngOnChanges() {
        this.updateComponent();
    }

    ngAfterViewInit() {
        this.isViewInitialized = true;
        this.updateComponent();
    }

    ngOnDestroy() {
        if (!!this.moduleRef)
            this.moduleRef.destroy();
    }
}

Sadly, I get this error from ComponentResolver: Error: Cannot resolve component using 'DashboardComponent'. at new BaseException$1 (http://localhost:63815/lib/@angular/compiler//bundles/compiler.umd.js:971:27)

I reckon that loading the module in Systemjs is not enough...so how do I tell ComponentResolver that I've downloaded a new component? The official documentation is still young and lacking...

On a side note, say that my Dashboard component loads additional stuff with imports...Systemjs will handle all that automatically, won't it?

Thanks in advance!

Community
  • 1
  • 1
Etchelon
  • 832
  • 11
  • 27

1 Answers1

0

This does not exactly answer your question.

BUT, We had a similar requirement and were loading components dynamically using SystemJs. It was all working fine until we started thinking about build and deployment strategies and came across Webpack

Since the value of moduleId is only known at runtime, so webpack will not be able to resolve the actual module components at compile time and will not bundle those files.

You will need to have static imports for your dynamic module components somewhere in your code if you want them to be bundled as part of your single app.js

Ajay Ambre
  • 89
  • 6