4

我有一个带有 FormControl 的组件,并订阅了它的值更改:

@Component(...)
export class FooComponent implements OnInit, OnDestroy {
  fooFormControl: FormControl;

  ...

  ngOnInit() {
    this.fooFormControl.valueChanges.subscribe(
      () => {...},
      () => {},
      () => {
        // never happens
      },
    );
  }

  ngOnDestroy() {
    //happens
  }
}

但是当组件被销毁时,FormControl 元素不会被销毁并且 onComplete 回调永远不会发生。

在组件销毁时销毁 FormControl 元素的正确方法是什么?

4

3 回答 3

2

FormControlobservables 不应该被完成,尽管如果有一些逻辑属于完成回调,则可以手动完成。

由于valueChanges是事件发射器并继承自 RxJS Subject,因此可以取消订阅或完成:

ngOnDestroy() {
  this.fooFormControl.valueChanges.complete();  
  // and/or
  this.fooFormControl.valueChanges.unsubscribe();
}

将来可能EventEmitter不会成为主题。这可能会导致重大更改,但目前它仅依赖于 RxJS。

于 2017-06-17T12:51:42.323 回答
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 {
}

请注意,这实际上并不传播完成。但它确实每次都给你一个新的来源主题。

于 2017-09-27T13:49:40.603 回答
0

你不能破坏你的表单控件。组件内的所有内容都将随之销毁,但事件可以保存在您的应用程序中。所以你可以取消订阅它的事件。

@Component(...)
export class FooComponent implements OnInit, OnDestroy {
  fooFormControl: FormControl;
  var subscriber;

  ...

  ngOnInit() {
    this.subscriber = this.fooFormControl.valueChanges.subscribe(
      () => {...},
      () => {},
      () => {
        // never happens
      },
    );
  }

  ngOnDestroy() {
    this.subscriber.unsubscribe();
  }
}
于 2017-06-17T10:13:51.737 回答