在Angular 2中为动态创建的组件处理@Input和@Output
Handle @Input and @Output for dynamically created Component in Angular 2
如何为Angular 2中动态创建的组件处理/提供@Input
和@Output
属性?
@Input
属性提供数据?此外,如何处理/订阅子组件提供的@Output
事件?例子:(两个组件都在同一个NgModule中)
AppComponent
@Component({
selector: 'app-root'
})
export class AppComponent {
someData: 'asdfasf'
constructor(private resolver: ComponentFactoryResolver, private location: ViewContainerRef) { }
createSub() {
const factory = this.resolver.resolveComponentFactory(SubComponent);
const ref = this.location.createComponent(factory, this.location.length, this.location.parentInjector, []);
ref.changeDetectorRef.detectChanges();
return ref;
}
onClick() {
// do something
}
}
子组件
@Component({
selector: 'app-sub'
})
export class SubComponent {
@Input('data') someData: string;
@Output('onClick') onClick = new EventEmitter();
}
您可以在创建组件时轻松地绑定它:
createSub() {
const factory = this.resolver.resolveComponentFactory(SubComponent);
const ref = this.location.createComponent(factory, this.location.length, this.location.parentInjector, []);
ref.someData = { data: '123' }; // send data to input
ref.onClick.subscribe( // subscribe to event emitter
(event: any) => {
console.log('click');
}
)
ref.changeDetectorRef.detectChanges();
return ref;
}
发送数据非常简单,只需执行ref.someData = data
,其中data
是您希望发送的数据。
从输出中获取数据也很容易,因为它是一个EventEmitter
,您可以简单地订阅它,并且您传入的clojure将在您从组件中emit()
获取值时执行。
我发现下面的代码从字符串(angular2生成组件从只是一个字符串),并创建了一个compileBoundHtml指令从它传递输入数据(不处理输出,但我认为同样的策略将适用,所以你可以修改这个):
@Directive({selector: '[compileBoundHtml]', exportAs: 'compileBoundHtmlDirective'})
export class CompileBoundHtmlDirective {
// input must be same as selector so it can be named as property on the DOM element it's on
@Input() compileBoundHtml: string;
@Input() inputs?: {[x: string]: any};
// keep reference to temp component (created below) so it can be garbage collected
protected cmpRef: ComponentRef<any>;
constructor( private vc: ViewContainerRef,
private compiler: Compiler,
private injector: Injector,
private m: NgModuleRef<any>) {
this.cmpRef = undefined;
}
/**
* Compile new temporary component using input string as template,
* and then insert adjacently into directive's viewContainerRef
*/
ngOnChanges() {
class TmpClass {
[x: string]: any;
}
// create component and module temps
const tmpCmp = Component({template: this.compileBoundHtml})(TmpClass);
// note: switch to using annotations here so coverage sees this function
@NgModule({imports: [/*your modules that have directives/components on them need to be passed here, potential for circular references unfortunately*/], declarations: [tmpCmp]})
class TmpModule {};
this.compiler.compileModuleAndAllComponentsAsync(TmpModule)
.then((factories) => {
// create and insert component (from the only compiled component factory) into the container view
const f = factories.componentFactories[0];
this.cmpRef = f.create(this.injector, [], null, this.m);
Object.assign(this.cmpRef.instance, this.inputs);
this.vc.insert(this.cmpRef.hostView);
});
}
/**
* Destroy temporary component when directive is destroyed
*/
ngOnDestroy() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
}
重要的修改是增加了:
Object.assign(this.cmpRef.instance, this.inputs);
基本上,它将你想要在新组件上的值复制到tmp组件类中,以便它们可以在生成的组件中使用。
可以这样使用:
<div [compileBoundHtml]="someContentThatHasComponentHtmlInIt" [inputs]="{anInput: anInputValue}"></div>
希望这能帮你省去大量的谷歌搜索。
createSub() {
const factory = this.resolver.resolveComponentFactory(SubComponent);
const ref = this.location.createComponent(factory, this.location.length,
ref.instance.model = {Which you like to send}
ref.instance.outPut = (data) =>{ //will get called from from SubComponent}
this.location.parentInjector, []);
ref.changeDetectorRef.detectChanges();
return ref;
}
SubComponent{
public model;
public outPut = <any>{};
constructor(){ console.log("Your input will be seen here",this.model) }
sendDataOnClick(){
this.outPut(inputData)
}
}
如果你知道你想要添加的组件的类型,我认为你可以使用另一种方法。
在你的应用根组件html:
<div *ngIf="functionHasCalled">
<app-sub [data]="dataInput" (onClick)="onSubComponentClick()"></app-sub>
</div>
在你的应用根组件typescript中:
private functionHasCalled:boolean = false;
private dataInput:string;
onClick(){
//And you can initialize the input property also if you need
this.dataInput = 'asfsdfasdf';
this.functionHasCalled = true;
}
onSubComponentClick(){
}
为@Input提供数据非常容易。你已经将你的组件命名为app-sub,它有一个名为data的@Input属性。可以这样提供这些数据:
<app-sub [data]="whateverdatayouwant"></app-sub>
相关文章:
- 组件生命周期问题/无法处理未定义的问题
- 如何向onClick事件处理程序传递一个接受参数的函数,并且仍然将该函数绑定到组件's”;这个“;上下文
- 如何正确处理依赖ViewChild和Angular 2中可观察到的数据的组件上的更改检测
- 在Flux中处理同一组件的多个实例
- 如何处理 React / Flux 组件中的状态转换
- 有没有更好的方法来处理窗口属性&React/Redux中的子组件
- 如何使用onClick处理程序在React组件中创建链接
- 将事件处理程序推送到父组件
- 如何处理需要子组件状态的Meteor数据
- 多个组件点击处理程序的反应性能[每个组件的点击处理程序与点击处理程序]
- Extjs 4,事件处理,范围,自定义组件
- React组件onClick处理程序不工作
- Gwd自定义组件及其事件处理程序
- 处理Twitter Flight组件的多个实例的事件
- React.js-通过事件处理程序更改所有者组件的状态
- ReactJS处理组件更改
- Angular-ui-router 0.3.2不能正确地处理组件
- 如何用redux处理组件状态
- vuejs 使用动态模板及其相关数据处理组件的更好方法
- 在 React 中处理组件状态的正确方法是什么?