如何在组件销毁时销毁反应式 FormControl?
Posted
技术标签:
【中文标题】如何在组件销毁时销毁反应式 FormControl?【英文标题】:How to destroy reactive FormControl on Component destroy? 【发布时间】:2017-11-20 01:29:36 【问题描述】:我有一个带有 FormControl 的组件并订阅了它的值变化:
@Component(...)
export class FooComponent implements OnInit, OnDestroy
fooFormControl: FormControl;
...
ngOnInit()
this.fooFormControl.valueChanges.subscribe(
() => ...,
() => ,
() =>
// never happens
,
);
ngOnDestroy()
//happens
但是当组件被销毁时,FormControl 元素不会被销毁,并且永远不会发生 onComplete 回调。
在组件销毁时销毁FormControl元素的正确方法是什么?
【问题讨论】:
【参考方案1】:FormControl
observables 不应该完成,但如果有一些属于完成回调的逻辑,可以手动完成。
由于valueChanges
是事件发射器,继承自RxJS Subject
,所以可以取消订阅或完成:
ngOnDestroy()
this.fooFormControl.valueChanges.complete();
// and/or
this.fooFormControl.valueChanges.unsubscribe();
EventEmitter
将来可能不会成为主题。这可能会导致重大更改,但目前它仅依赖于 RxJS。
【讨论】:
更新:valueChanges 不再有 unsubscribe() 方法。但是 FormControl.valueChanges.subscribe() 会重新运行一个订阅,以后可以存储和取消订阅。this.mySubscription = this.fooFormControl.valueChanges.subscribe(…); this.mySubscription.unsubscribe()
...它也没有 complete() 方法。在 Angular 11 版本中 valueChanges 是 Observable,而不是 EventEmitter.【参考方案2】:
这里有两个想法可能会对您有所帮助。不确定它们是否是“正确的方法”,但到目前为止它对我来说效果很好。除此之外,我像往常一样取消订阅 ngOnDestroy。
#1 通过 takeUntil 引入您自己的主题来强制完成
在 TypeScript 中,valueChanges 属性属于 Observable 类型。如果您不想解决这个问题并进入主题,那么您可以使用 takeUntil 运算符来介绍您自己的主题。这将允许您强制在 valueChanges observable 之上的级别传播完成。重要的是不要将 takeUntil 运算符放在 switchmap 之前,否则切换到 observable 将继续并且您的订阅不会被取消!出于这个原因,我把它放在订阅运算符之前。
这是一个例子:
const stop = new Subject();
// simulate ngOnDestroy
window.setTimeout(() =>
stop.next();
stop.complete();
, 3500);
Observable
.interval(1000)
.takeUntil(stop)
.subscribe(
() => console.log('next'); ,
() => console.log('error'); ,
() => console.log('complete');
);
这是一个工作示例:https://rxviz.com/v/RoQNBnOM
#2 将 FormBuilder 添加到组件的提供者列表中
这是我通常做的。实际上,我通常将表单封装在使用 FormBuilder 的服务中,但效果是一样的。在此级别提供服务将在每次创建组件时销毁并重新创建服务。我开始这样做是因为我一直有一些奇怪的错误,这些错误是由在组件生命周期之后持续存在的 valueChanges 创建的可观察流引起的。当组件被重新创建时,它们会被重新订阅。
这是一个例子:
@Component(
selector: 'my-form',
templateUrl: './my-form.component.html',
styleUrls: ['./my-form.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ FormBuilder ] // <-- THIS PART
)
export class MyFormComponent implements OnInit, OnDestroy
请注意,这实际上并不传播完成。但它确实每次都会给你一个新的来源主题。
【讨论】:
【参考方案3】:你不能破坏你的表单控件。组件内的所有内容都将随之销毁,但事件可以保存在您的应用程序中。所以你可以取消订阅它的事件。
@Component(...)
export class FooComponent implements OnInit, OnDestroy
fooFormControl: FormControl;
var subscriber;
...
ngOnInit()
this.subscriber = this.fooFormControl.valueChanges.subscribe(
() => ...,
() => ,
() =>
// never happens
,
);
ngOnDestroy()
this.subscriber.unsubscribe();
【讨论】:
以上是关于如何在组件销毁时销毁反应式 FormControl?的主要内容,如果未能解决你的问题,请参考以下文章
在自定义 Angular 组件中访问 FormControl