valueChanges observable似乎在订阅之前订阅了数据

时间:2018-01-16 00:47:26

标签: angular rxjs angular-reactive-forms

我正在创建一个动态创建的被动表单。我以可观察的形式(来自主题)从服务获取数据,并且希望在创建后订阅表单valueChanges。当我第一次设置时,我订阅了每个服务的observable和valueChanges,但是我看到了表单创建的每一步的数据,这是有意义的,因为两个服务可观察量可以在之后发出。

所以我重构了使用Observable.zip的设置,据我所知,它使代码成为线性的,所以在我进入valueChanges订阅之前应该先设置表单,但我仍然看到形式创造发生的每一步。

this.filterForm = this.formBuilder.group({
    'search': '',
    'types': this.formBuilder.group({}),
    'dates': this.formBuilder.array([]),
});

let formData = Observable.zip(
    this.eventService.getTypes(),
    this.eventService.getDates()
);
formData.forEach(data => {
    let types = data[0],
        dates = data[1];
    types.forEach(type => {
        this.types.push(type);
        (<FormGroup>(this.filterForm.get('types'))).addControl(type, new FormControl())
    });
    dates.forEach(date => {
        this.dates.push(date.format('dddd'));
        (<FormArray>(this.filterForm.get('dates'))).push(new FormControl(false))
    });
    this.filterForm.valueChanges.subscribe(data => console.log(data));
});

当我说我看到表格正在构建的价值时,我的意思是:

{search: "", types: {…}, dates: Array(0)}
{search: "", types: {…}, dates: Array(1)}
{search: "", types: {…}, dates: Array(2)}
{search: "", types: {…}, dates: Array(3)}
{search: "", types: {…}, dates: Array(4)}
{search: "", types: {…}, dates: Array(5)}

在类型字段构建之前,它之前有十几个条目。

这是应该如何工作的?我的目标是在构建表单之后订阅,因此我只在用户更改表单时获取值。

2 个答案:

答案 0 :(得分:1)

我有一个不同的建议。在RxJS中,除了订阅链的subscribe()方法之外,还有内部订阅的toPromise()forEach()。见https://github.com/ReactiveX/rxjs/blob/master/src/internal/Observable.ts#L223

而且我认为这就是发生在你身上的事情。 forEach方法订阅formData Observable并为每个发出的值调用其回调。但是你也在回调中使用this.filterForm.valueChanges.subscribe,这意味着每次formData发出一个值时你都会创建一个新的订阅。

我不知道您的代码应该做什么,但我认为您可以将其重组为以下内容:

Observable.zip(
    this.eventService.getTypes(),
    this.eventService.getDates()
  )
  .do(data => {
    let types = data[0],
        dates = data[1];
    types.forEach(type => {
        this.types.push(type);
        (<FormGroup>(this.filterForm.get('types'))).addControl(type, new FormControl())
    });
    dates.forEach(date => {
        this.dates.push(date.format('dddd'));
        (<FormArray>(this.filterForm.get('dates'))).push(new FormControl(false))
    });
  })
  .switchMap(() => this.filterForm.valueChanges))
  .subscribe(data => console.log(data));

答案 1 :(得分:0)

不要在OnInit生命周期钩子中订阅。创建一个处理订阅的方法,并在OnInit中声明表单模型后调用该方法。

更常见的是,您可以使用skip()运算符跳过特定数量的排放,或使用过滤器/映射仅在满足特定条件/结构后处理排放。