Angular 6嵌套请求无法传递正确的数据

时间:2019-07-10 16:14:20

标签: angular rxjs angular6

我正在订阅两个彼此嵌套的httprequest。我的目的是让模型数组充满第一个请求中的对象,而不是发出第二个请求并订阅它,以便我可以从第一个请求中修改对象。 问题是,在第二个请求中,我正在执行许多对象操作,当我将其保存到存储中时,这些操作就不存在了。

 private _patientListPoll$ = interval(this.listRequestInterval).pipe(
startWith(0),
map(() => this.getPatientList().subscribe(model=>{
  this.model = model.map(a => Object.assign({}, a));
  const linkedIds = this.model.filter(x => x.linkedUserId && x.statusId === 2).map(x => x.linkedUserId);
  this.deviceDataService.getLastActivity(linkedIds).subscribe(data=>{
    for (const item of data) {
      let patient = this.model.find(x => x.linkedUserId === item.userId);
      if (patient) {
        Object.assign(patient, { lastActivity: item.lastUploadDate });
        const diff = Math.abs(new Date().getTime() - new Date(patient.lastActivity).getTime());
        const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
        if (diffDays <= 7) {
          Object.assign(patient, { filterStatus: 4 });
        }
        let id = patient.id;
        let index = this.model.findIndex(item => item.id === id)
        this.model.splice(index, 1, patient)
        console.log(this.model)
      }
    }
    this.patientDataStore.savePatientData(this.model);
  })

}), share()));

任何想法都很棒。.

在bryan60的大力帮助下,我明白了

private _patientListPoll$ = timer(0, this.listRequestInterval).pipe(
switchMap(() => this.getPatientList()),
switchMap(model => {
  const linkedIds = model.filter(x => x.linkedUserId && x.statusId === 2).map(x => x.linkedUserId);
  this.trialService.getPatientTrialStatusList().subscribe(data=>{
    if (data) {
      for (const item of data.result) {
        for (const patient of model) {
          if (item.id === patient.id) {
            Object.assign(patient, {trialStatusId: item.state});
            console.log(patient)
            break;
          }
        }
      }
    }
  })
  return this.deviceDataService.getLastActivity(linkedIds).pipe(
    map(data => {
      for (const item of data) {
        let patient = model.find(x => x.linkedUserId === item.userId);
        if (patient) {
          Object.assign(patient, {lastActivity: item.lastUploadDate});
          const diff = Math.abs(new Date().getTime() - new Date(patient.lastActivity).getTime());
          const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
          if (diffDays <= 7) {
            Object.assign(patient, {filterStatus: 4});
          }
          let id = patient.id;
          let index = model.findIndex(item => item.id === id);
          model.splice(index, 1, patient);
        }
      }
      return model;
    })
  );
}),
tap(model => {
  this.patientDataStore.savePatientData(model);
  this.model = model;
}),
share());

2 个答案:

答案 0 :(得分:1)

您正在使用“嵌套订阅”反模式,这正引起您的问题。相反,请使用适当的高阶可观察变量来避免嵌套订阅。

private _patientListPoll$ = timer(0, this.listRequestInterval).pipe( // prefer timer to interval and starts with
  switchMap(() => // use switchMap to subscribe to inner observable and cancel previous subscriptions if still in flight
    forkJoin(this.getPatientList(), this.trialService.getPatientTrialStatusList())), //forkJoin runs multiple observables in parrallel and returns an array of the values
  switchMap(([model, trialData]) => { // now I have both model and trial data 
    // this.model = model.map(a => Object.assign({}, a)); don't produce side effects
    use it as needed...
    if (trialData) {
      for (const item of trialData.result) {
        for (const patient of model) {
          if (item.id === patient.id) {
            Object.assign(patient, {trialStatusId: item.state});
            console.log(patient)
            break;
          }
        }
      }
    }

    const linkedIds = model.filter(x => x.linkedUserId && x.statusId === 2).map(x => x.linkedUserId);
    return this.deviceDataService.getLastActivity(linkedIds).pipe(
      map(data => { // now do your mapping since you've got both
        for (const item of data) {
          let patient = model.find(x => x.linkedUserId === item.userId);
          if (patient) {
            Object.assign(patient, { lastActivity: item.lastUploadDate });
            const diff = Math.abs(new Date().getTime() - new Date(patient.lastActivity).getTime());
            const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
            if (diffDays <= 7) {
              Object.assign(patient, { filterStatus: 4 });
            }
            let id = patient.id;
            let index = model.findIndex(item => item.id === id)
            model.splice(index, 1, patient)
            console.log(model)
          }
        }
        return model;
      })
    );
  }),
  tap(model => { // prefer tap for side effects if absolutely necessary
    this.patientDataStore.savePatientData(model);
    this.model = model;
  }),
  share()
);

这也大大清理了您的管道。

与眼前的问题并不严格相关,但是您可以稍微整理/简化地图逻辑:

  map(data => 
    model.map(patient => {
      let toAssign = {};
      const item = data.find(x => x.userId === patient.linkedUserId);       
      if (item) { 
        const lastActivity = item.lastUploadDate;
        const diff = Math.abs(new Date().getTime() - new Date(lastActivity).getTime());
        const diffDays = Math.ceil(diff / (1000 * 3600 * 24));
        const filterStatus = (diffDays < 7) ? 4 : patient.filterStatus;
        toAssign = {
          lastActivity,
          filterStatus
        };
      }
      const trial = (trialData || []).find(t => t.id === patient.id);
      if (trial) {
        Object.assign(toAssign, {trialStatusId: trial.state});
      }
      return Object.assign({}, patient, toAssign);
    })
  )

答案 1 :(得分:0)

如果可以的话,我会用一条评论,但我还没有足够的代表。据我所知,您在)之后错放了一个share()并放错了位置,应该放在最后一个})之后,这可能会导致map运算符出现问题。

之前

...
}), share()));

之后

...
})), share()));

程序是否给出任何错误或任何其他信息?我建议使用浏览器调试器放置断点并逐步运行该函数以查看发生了什么。