Angular 6 вложенных запросов не доставляют правильные данные - PullRequest
0 голосов
/ 10 июля 2019

Я подписываюсь на два 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 s я понял (а)

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 ]

1 голос
/ 10 июля 2019

вы используете анти-паттерн "вложенная подписка" прямо сейчас, который вызывает вашу проблему. Вместо этого избегайте вложенных подписок, используя надлежащие наблюдаемые более высокого порядка.

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);
    })
  )
0 голосов
/ 10 июля 2019

Я бы использовал комментарий, если бы мог, но мне пока не хватает представителя. Из того, что я видел, у вас есть неуместный ), который идет сразу после share() и должен стоять после последнего }), что может вызвать проблемы у оператора map.

До

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

* После 1013 *

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

Дает ли программа какую-либо ошибку или дополнительную информацию? Я рекомендую использовать отладчик браузера для установки точек останова и шаг за шагом запустить функцию, чтобы увидеть, что происходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...