所以我有一个带有@Output
事件的from的Component,触发提交,如下所示:
@Component({
selector: 'some-component',
templateUrl: './SomeComponent.html'
})
export class SomeComponent{
@Input() data: any;
@Output() onSubmit: EventEmitter<void> = new EventEmitter<void>();
constructor(private someService: SomeService) {}
submitForm(): void{
this.someService.updateBackend(this.data, ()=>{
this.onSubmit.emit();
});
}
}
我正在使用ngFor
创建此组件的多个元素:
<template let-data ngFor [ngForOf]="dataCollection">
<some-component [data]="data" (onSubmit)="doSomthing()"></some-component>
</template>
最后一个缺失部分是提交时使用的服务:
@Injectable()
export class SomeService{
constructor() {}
updateBackend(data: any, callback: () => void): void{
/*
* updating the backend
*/.then((result) => {
const { errors, data } = result;
if (data) {
callback();
}
})
}
}
在submitForm()
函数的开头,this.onSubmit.observers
是一个包含一个观察者的数组,就像它应该的那样。
一旦到达调用this.onSubmit.emit()
的回调方法,this.onSubmit.observers
就是一个包含ZERO观察者的数组。
SomeService.updateBackend
中的后端,则它完全正常,observers
仍然是包含一个观察者的数组!ngFor
并且只显示一个<some-element>
它也可以正常工作,将一个观察者保留在回调范围内的this.onSubmit.observers
中! 知道我做错了什么?
提前致谢!
感谢@ StevenLuke关于记录ngOnDestroy
SomeComponent
的评论我发现它在发射之前被摧毁了。
实际上,当SomeService.updateBackend
完成时它正在做的第一件事是销毁该组件的所有实例并重新创建它们!
这是观察者改变的原因!为什么会这样?
答案 0 :(得分:5)
如果在* ngFor中提供trackBy函数来识别dataCollection中的项目,它将不会销毁和初始化。您的模板将是:
<some-component *ngFor="let data of dataCollection;trackBy:trackByFunction"
[data]="data" (onSubmit)="doSomthing()"></some-component>
trackByFunction看起来像:
trackByFunction(index, item) {
return item ? item.id : undefined;
}
因此,即使dataCollection中的项目是一个新对象,如果它的id与前一个集合中的id匹配,* ngFor将更新[data]但不会销毁并初始化该组件。
答案 1 :(得分:1)
感谢@GünterZöchbauer的评论我发现案例是ngFor
绑定的数据被新实例替换为更新后端,因此,它重新渲染了它的子组件导致重新初始化(destory) + init)它们,这使得Component的实例被覆盖。
为了解决这个问题,我必须将dataCollection
放在一个单独的服务中,为父组件ngOnInit
获取它,保存它不会导致ngFor
的重新呈现,只有在子组件执行结束后再次获取其数据
希望它对某人有帮助!