Angular2:从组件中获取数据,通过ComponentFactoryResolver创建

时间:2016-12-22 13:01:15

标签: angular factory eventemitter

我有一个网格组件,我想通过向每列添加过滤器来扩展它。事实上,我对每列都有不同的过滤器类型,如简单的文本输入,选项过滤器,日期范围过滤器等。所以,目前我想创建一个过滤器工厂。我只想路径过滤器类型并获得所需的过滤器组件。我正在关注这个guide,这就是我到目前为止所做的。

工厂组件:

import {
    Component, Input, Inject, ViewContainerRef, ViewChild, ReflectiveInjector, ComponentFactoryResolver
} from '@angular/core';
import mod = require('../../env-bootstrap');
import {OptionsFilter} from "./options/options.filter";
import {BlankFilter} from "./blank/blank.filter";

@Component(mod.check({
    selector: 'filters-factory',
    moduleId: module.id,
    entryComponents: [OptionsFilter, BlankFilter],
    template: '<div #dynamicComponentContainer></div>'
}))

export class FiltersFactory {
    constructor(@Inject(ComponentFactoryResolver) private resolver: ComponentFactoryResolver) {}
    currentComponent = null;

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

    @Input() set componentData(data: {componentName: any, inputs: any }) {
        if (! data) {
            return;
        }

        switch (data.componentName) {
            case 'name':
                component = OptionsFilter;
                break;
            default:
                component = BlankFilter;
        }

        // Inputs need to be in the following format to be resolved properly
        let inputProviders = Object.keys(data.inputs).map((inputName) => {
            return {provide: inputName, useValue: data.inputs[inputName]};
        });
        let resolvedInputs = ReflectiveInjector.resolve(inputProviders);

        // We create an injector out of the data we want to pass down and this components injector
        let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicComponentContainer.parentInjector);

        // We create a factory out of the component we want to create
        let factory = this.resolver.resolveComponentFactory(component);

        // We create the component using the factory and the injector
        let component = factory.create(injector);

        // We insert the component into the dom container
        this.dynamicComponentContainer.insert(component.hostView);

        // Destroy the previously created component
        if (this.currentComponent) {
            this.currentComponent.destroy();
        }

        this.currentComponent = component;
    }
}

我的OptionsFilter组件:

import {Component, Injector, Inject, Output, EventEmitter } from '@angular/core';
import mod = require('../../../env-bootstrap');

@Component(mod.check({
    selector: 'options-filter',
    moduleId: module.id,
    styleUrls: 'share/filters/options/options.css',
    templateUrl: 'share/filters/options/options.html'
}))

export class OptionsFilter {
    showNum = 0;
    constructor(@Inject(Injector) private injector: Injector) {
        this.showNum = this.injector.get('showNum');
    }

    @Output() filterValue = new EventEmitter();

    private onChange(option) {
        this.filterValue.emit(option);
    }
}

以下是我如何将工厂组件添加到网格

<td *ngFor="let columnName of columnNames">
    <filters-factory [componentData]="{ componentName: columnName ,inputs: { showNum: 9} }"></filters-factory>
</td>

我的FilterOptions模板

<select (change)="onChange($event)">
    <option disabled>Options</option>
    <option>33</option>
    <option>33</option>
</select>

因此,现在主要的是从option到工厂组件的html select标记路径OptionsFilter值。有可能吗?

1 个答案:

答案 0 :(得分:1)

在FiltersFactory中,您可以使用

访问动态组件的字段
console.log(this.currentComponent.instance.option);

为此,您需要option中的媒体资源OptionsFilter,目前您只有一个@Output()

您不能对动态添加的组件使用绑定,因此@Input()@Output()毫无意义。

您也可以始终使用共享服务与动态添加的组件进行通信,如https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service中所述