[Angular 2] Generate Angular 2 Components Programmatically with entryComponents & ViewContainerRef

You can generate Angular 2 components using a combination of ViewContainer and ComponentFactory, but you must always remember to add the components you want to generate to your list of entryComponents otherwise the compiler will optimize the component class out of your project.html

 

ViewChild:api

For example, in HomComponent, we created a div with ref "#container", if you log out the element we can see:this

import {Component, ViewChild} from '@angular/core';
import {SimpleService} from "../../serivces/simple.service";

@Component({
    moduleId: module.id,
    selector: 'home',
    template: '<div #container></div>'
})
export class HomeComponent {

    @ViewChild('container') container;

    constructor(private simpleService: SimpleService) {
    }

    ngAfterContentInit(){

    }

}

It is a native Element. spa

 

Actually you can View the child in other different way:3d

    @ViewChild('container', {
        read: ViewContainerRef
    }) container;

"ViewContainerRef": Represents a container where one or more Views can be attached.code

 

For example we now want to create component Programmatically:component

import {Component, ViewChild, ViewContainerRef, ComponentFactoryResolver} from '@angular/core';
import {WidgetThree} from "../widgets/widget-three.component";

@Component({
    moduleId: module.id,
    selector: 'home',
    template: '<div #container></div>'
})
export class HomeComponent {

    @ViewChild('container', {
        read: ViewContainerRef
    }) container;

    constructor(private resolver: ComponentFactoryResolver) {
    }

    ngAfterContentInit(){

        const WidgetFactory = this.resolver.resolveComponentFactory(WidgetThree);
        this.container.createComponent(
            WidgetFactory
        )
    }

}

See https://angular.io/docs/ts/latest/api/core/index/ViewContainerRef-class.htmlhtm

But now, it won't work:blog

It says it cannot find WidgetThree, even we already define in Module:three

import { NgModule} from '@angular/core';
import { CommonModule } from '@angular/common';
import {WidgetOneComponent} from './widget-one.component';
import {WidgetTwoComponent} from './widget-two.component';
import {WidgetThree} from './widget-three.component';

@NgModule({
    imports: [CommonModule],
    declarations: [WidgetOneComponent, WidgetTwoComponent, WidgetThree],
    exports: [WidgetOneComponent, WidgetTwoComponent, WidgetThree, CommonModule]
})
export class WidgetsModule {

}

 

The problem for that is because Angualr2 optimize the imports component, check whether it is used in template, if not, then remove the component from the bundle file. Because in HomeComponent tempalte, we didn't use WidgetThree compoennt, so it was removed.

 

To solve the problem, we can use "entryComponents":

import { NgModule} from '@angular/core';
import { CommonModule } from '@angular/common';
import {WidgetOneComponent} from './widget-one.component';
import {WidgetTwoComponent} from './widget-two.component';
import {WidgetThree} from './widget-three.component';

@NgModule({
    imports: [CommonModule],
    declarations: [WidgetOneComponent, WidgetTwoComponent, WidgetThree],
    entryComponents: [WidgetThree],
    exports: [WidgetOneComponent, WidgetTwoComponent, WidgetThree, CommonModule]
})
export class WidgetsModule {

}

 

"entryComponents" just tell angular, no matter what, keep the componet into the bundle, don't remove it.

And now, we can actually create multi WidgetThree component programmatically:

export class HomeComponent {

    @ViewChild('container', {
        read: ViewContainerRef
    }) container;

    constructor(private resolver: ComponentFactoryResolver, private simpleService: SimpleService) {
    }

    ngAfterContentInit(){
        const WidgetFactory = this.resolver.resolveComponentFactory(WidgetThree);
        this.container.createComponent(WidgetFactory);
        this.container.createComponent(WidgetFactory);
        this.container.createComponent(WidgetFactory);
        this.container.createComponent(WidgetFactory);
        this.container.createComponent(WidgetFactory);
    }

}
相關文章
相關標籤/搜索