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