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

Angular2: get data from component, created via ComponentFactoryResolver

我有一个网格组件,我想通过向每一列添加过滤器来扩展它。事实上,我对每一列都有不同的过滤器类型,比如简单的文本输入、选项过滤器、日期范围过滤器等。所以,目前我想创建一个过滤器工厂。我只想定位一个过滤器类型并获取所需的过滤器组件。我一直在关注这个 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>

所以现在对我来说主要的事情是从 OptionsFilter 到工厂组件的 html select 标签的路径 option 值。可能吗?

在 FiltersFactory 中,您可以使用

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

为此你需要 OptionsFilter 属性 option,目前你只有 @Output()

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

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

中所述