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

Angular valueChanges observable似乎在订阅之前订阅了数据,angular,rxjs,angular-reactive-forms,Angular,Rxjs,Angular Reactive Forms,我正在创建一个动态创建的被动表单。我以可观察的形式(来自主题)从服务中获取数据,并希望在创建表单后订阅表单的valueChanges。当我第一次设置它时,我订阅了服务的每个观察值和valueChanges,但是我看到了表单创建的每个步骤中的数据,这是有意义的,因为两个服务观察值可以在创建之后发出 因此,我对设置进行了重构,使用了Observable.zip,据我所知,它使代码线性化,因此应该在我获得valueChanges订阅之前设置表单,但我仍然看到表单创建的每一步都在进行 this.filt

我正在创建一个动态创建的被动表单。我以可观察的形式(来自主题)从服务中获取数据,并希望在创建表单后订阅表单的
valueChanges
。当我第一次设置它时,我订阅了服务的每个观察值和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));
});
在类型字段生成时,前面有十几个条目


这应该是这样的吗?我的目标是在表单生成后订阅,因此我只在用户更改表单时获取值。

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


更一般地说,您可以使用skip()操作符跳过特定数量的排放,或者使用过滤器/映射仅在满足特定条件/结构后处理排放

我有一点不同的建议。在RxJS中,除了订阅链的
subscribe()
方法外,还有内部订阅的
toPromise()
forEach()
。看

我想这就是发生在你身上的事。
forEach
方法订阅可观察的
formData
,并为每个发出的值调用其回调。但是您也在回调中使用了
this.filterperform.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));
Observable.zip(
this.eventService.getTypes(),
this.eventService.getDates()
)
.do(数据=>{
设类型=数据[0],
日期=数据[1];
types.forEach(type=>{
此.types.push(类型);
((this.filterForm.get('types')).addControl(type,newformcontrol())
});
dates.forEach(日期=>{
this.dates.push(date.format('dddddd');
((this.filterperform.get('dates')).push(newformcontrol(false))
});
})
.switchMap(()=>this.filterForm.valueChanges))
.subscribe(数据=>console.log(数据));

您可以在
afterViewInit
生命周期内尝试订阅为什么
afterViewInit
?这与视图没有任何关系;订阅不应该在我订阅之前为我提供值吗?您正在与
formBuilder
相同的级别上运行订阅。这意味着您在filterForm初始化时订阅了它,并且很可能是在它完成构建之前订阅的(因此订阅的值在开始时将为空)。由于正在生成的表单是生成视图的一部分,因此在初始化视图后订阅应该是安全的。希望这有帮助!我认为这意味着当我点击像
addControl
?因为唯一有意义的方法是表单异步构建,允许订阅在表单初始化之前到来。我将移动代码以使其正常工作,但我仍然不明白它为什么会这样运行:/Correct,这都是异步的,即使我将订阅移动到另一个方法,这是有意义的,它不具有与上面代码相同的效果吗?如果它是同步的,它仍然会在那个时候触发。我想我很困惑,为什么表单生成后的订阅会向我显示正在生成的表单的各个阶段。当你说“正在生成的表单的各个阶段”时,我会在问题中添加控制台输出。我很喜欢这个想法,但根据VSCode,
do
从zip返回时不存在吗?只有
dowhile
。在RxJS 5.4中,您需要使用
import'RxJS/add/operator/do'
导入它,或者在RxJS 5.5中,它被重命名为
tap
tap
被重命名为可出租版本,但
do
的流畅版本仍然存在。奇怪的是,它并没有让我按照你的建议去做,但通过水龙头的管道似乎已经解决了这个问题。考虑到
zip
forEach
导致了问题,如回答中所述,我使用
forkJoin
尝试了解决方案,并得到了相同的问题。我仍然不知道发生了什么,这让我很困扰,但我想现在它起作用了:/
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));