使用NGRX& amp;同步处理依赖于另一个Observable的Observable.角度的 [英] Synchronously process an Observable dependent on another Observable using NGRX & Angular

查看:36
本文介绍了使用NGRX& amp;同步处理依赖于另一个Observable的Observable.角度的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 ngOnInit(): void {
    this.store.dispatch(new patients.Load([]));
    this.patients$ = this.store.select(fromPatients.getAll);

    this.patients$.map(p =>{ //  patients$: Observable<Patient[]>;
      this.rows = p.map(pat => { //I use this on the front end
        return {
          username: pat.username,
          id: pat.id,
          hasAlert: this.hasAlerts(pat), //made this an observable for the async pipe in view
          settings: "Settings"
        };
      });
      this.table.recalculatePages();
      console.log(this.rows);
      console.log("This happens first");
    }).subscribe();

  }
  hasAlerts(pat: Patient): Observable<boolean> {
    var shouldAlert$ = Observable.of(false);//this value is always taken

      this.observations2$ = this.dataService.fetchItems<Observation>(
        "Observation",
        null,
        pat.id// How would i pass this in with mergeMap()?  
      );

      this.observations2$.subscribe(curObservation => {
        if (curObservation.category.coding[0].code == "GlucoseEvent"){ 
          shouldAlert$ = Observable.of(true);
          console.log("should alert$", shouldAlert$);
        }
      });

    console.log("this happens second");
    return shouldAlert$;
  }

在上面的代码中,我解析了一个可观察到的名为患者$",其中包含一系列患者.然后,我将这些患者映射到我在客户端上显示的名为this.rows的对象数组.

In the code above I parse an observable called patients$ that has an array of patients. I am then mapping those patients to an object array called this.rows that I show on my client.

我的问题涉及hasAlert属性,该属性在对hasAlerts()的方法调用中处理另一个可观察的自身.hasAlerts()的此方法调用不会同步发生,因此console.log("this first first");在hasAlerts方法可以执行If语句中的逻辑以确定是否将其设置为true或false之前发生,而是仅使用hasAlerts()第一行中初始化的值.由console.log确认(这第二次发生");被第二次显示.

My problem involves the hasAlert property which processes another observable itself in the method call to hasAlerts(). This method call to hasAlerts() does not happen synchronously so the console.log("this happens first"); occurs before my hasAlerts method can do the logic in the If statement to decide whether it should be set to true or false, instead it just uses the value it is initialized to in the first line of hasAlerts(). Confirmed by the console.log("this happens second"); being displayed second.

hasAlerts()可能会返回一个布尔值,而不是一个可观察到的值,我试图通过使用前端的asycn管道来查看是否可以解决我的问题(它没有).

hasAlerts() could return a boolean not an observable, I was trying to see if that would solve my problem using an asycn pipe on the front end (it didnt).

我相信解决此问题的方法包括使用mergemap,但是我不确定hasAlerts方法所需的pat.id如何传递?也许这不是通过异步执行此代码来解决我当前问题的正确方法.

I believe the way to solve this involves using mergemap however I am not sure how i would pass in the pat.id that the hasAlerts method needs? Or maybe this is not the correct approach to solve my current problem with the asynchronous execution of this code.

我目前正在尝试使用此这个关于mergemap的问题解决了我的问题,但是传递了has.Alerts中第二个可观察到的pat.id,我还没有弄清楚. 1

I am currently trying to use this this question about mergemap to solve my issue but passing the pat.id that the second observable in hasAlerts I haven't figured out yet. 1

按照Piccis的想法更新了代码.

this.patients$.map(p =>{ //  patients$: Observable<Patient[]>;
      this.rows = p.map(pat => { //I use this on the front end
        return {
          username: pat.username,
          id: pat.id,
          hasAlert: false, //set the default value
          settings: "Settings"
        };
      })
    }).do(data => console.log("data1",data))
  //   .switchMap(p => Observable.from(p))
  //   .do(data => console.log("data2",data)) // creates a stream of Observable<Patient>
  //   .mergeMap(patient => this.dataService.fetchItems<Observation>(
  //       "Observation",
  //       null,
  //       "pat..frank"//patient[0].id//"pat..frank"//patient.id// patient should be your guy          
  //     )
  //     .map(curObservation => {
  //       console.log("currOBS",curObservation); 

  //       if (curObservation.category.coding[0].code == "GlucoseEvent"){
  //         var shouldAlert$ = true;
  //         console.log("should alert$", shouldAlert$);
  //       }
  //     })
  //   ).do(data => console.log(data))
  //  .toArray()
   .subscribe(
      patients => {
          this.table.recalculatePages();
          console.log(this.rows);
      }
   )

Data1返回一组患者.我需要在中间注释掉,因为switchmap行出现语法错误,说无法将类型为'void'的参数分配给类型为'ArrayLike< {}>'的参数"

Data1 returns an array of patients. I need to comment out the middle because there is a syntax error with the switchmap line saying " Argument of type 'void' is not assignable to parameter of type 'ArrayLike<{}>'"

推荐答案

基本问题是合并两个异步调用,可以使用 zip()完成.

The basic problem is combining two async calls, can be done with zip().

(注意,我最初使用 forkJoin()发布了一个解决方案,但这不适用于ngrx select(),因为选择永远不会完成-因此forkJoin永远不会火灾).

(Note, I originally posted a solution with forkJoin(), but this does not work with ngrx select(), since the select never completes - therefore forkJoin never fires).

将从第一次获取返回的 Observable< Patient []> 转换为 Observable< Patient> ,因为它对zip运算符更方便.

Convert the Observable<Patient[]> returned from the first fetch to Observable<Patient>, as it is more convenient for the zip operator.

下一个问题是第二异步取决于第一异步(pat.id)的结果-使用 concatMap()构建该异步对象.

Next problem is 2nd async is dependent on result of 1st async (pat.id) - build that one with concatMap().

(注意,我最初建议使用 mergeMap(),但是 concatMap()保证hasAlert $的顺序与Patient $中的顺序相同.这很重要,因为 this.dataService.fetchItems()可能会无序返回单个提取操作).

(Note, I originally suggested mergeMap(), however concatMap() guarantees the same ordering of hasAlert$ as in patient$. This is important, since this.dataService.fetchItems() may return individual fetches out of order).

import { zip } from 'rxjs/observable/zip';
...

ngOnInit(): void {
  this.store.dispatch(new patients.Load([]));

  const patient$ = this.store.select(fromPatients.getAll)
    .mergeMap(value => value); // convert from Observable<patients[]> to Observable<patient>

  const hasAlert$ = patient$.concatMap(patient => {
    return this.dataService.fetchItems<Observation>('Observation' null, patient.id)
      .map(curObservation => curObservation.category.coding[0].code === 'GlucoseEvent')
    );
  })

  zip(patient$, hasAlert$)  // combine values from both asyncs
    .map(([patient, hasAlert]) => {
      return {
        username: patient.username,
        id: patient.id,
        hasAlert,
        settings: "Settings"
      };
    })
    .toArray()
    .subscribe(rows => {
      this.rows = rows;
      this.table.recalculatePages();
    }); 
}


测试答案片段的Rx逻辑.


Testing the Rx logic of the answer snippet.

console.clear();
const { zip, from, of } = Rx.Observable;
/* in Angular with Rxjs v5.5, use 
  import { zip } from 'rxjs/observable/zip';
  import { from } from 'rxjs/observable/of';
  import { of } from 'rxjs/observable/from';
*/

// Simulate other observables
const storeSelectFromPatientsGetAll$ = () =>
  of([{id: 1, username: 'Fred'}, {id: 2, username: 'Joan'}]);
const dataServiceFetchItems$ = (type, something, id) =>
  of({ category: { coding: [{code: 'GlucoseEvent'}] }})

// Testing the ngOnInit code
const patient$ = storeSelectFromPatientsGetAll$()
  .mergeMap(value => value);

const hasAlert$ = patient$.concatMap(patient => {
  return dataServiceFetchItems$('Observation', null, patient.id)
    .map(curObservation => curObservation.category.coding[0].code === 'GlucoseEvent');
});

zip(patient$, hasAlert$)  // wait for resolution of both asyncs
  .map(([patient, hasAlert]) => {
    return {
      username: patient.username,
      id: patient.id,
      hasAlert,
      settings: 'Settings'
    };
  })
  .toArray()
  .subscribe(rows => {
    console.log(rows);
  });

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>

这篇关于使用NGRX&amp; amp;同步处理依赖于另一个Observable的Observable.角度的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆