简体   繁体   中英

append new observables to array of observables?

I am trying to avoid the following:

switchMap(([action, state]) =>
  from(TodosDB.getAll()).pipe(
    map(
      (todos) => onQueryTodoDone({ items: todos }),
      catchError((err) => of(onQueryTodoFail({ error: err })))
    )
  )
),

to something more linear like like we do with combineLatestFrom in ngrx. So far I tried to do the below. But the promise does not seem to work.

withLatestFrom(
  from(TodosDB.getAll())
),

and

withLatestFrom(
  from(TodosDB.getAll()).pipe(
    map((todos) => onQueryTodoDone({ items: todos }))
  )
)

Any ideas how to deal with this scenario without nesting pipe map in a switchMap?

PS: this might be obvious to you but I don't know much and I looked up on the inte.net and found withLatestFrom but not sure what I am missing.

EDIT: this is the best I got so far:

switchMap(([action, state]) =>
  forkJoin([of(action), of(state), TodosDB.getAll()])
),
map(
  ([action, state, todos]) => onQueryTodoDone({ items: todos }),
  catchError((err) => of(onQueryTodoFail({ error: err })))
),

The above is better but I have no idea if that can cause issues later. But hopefully I was able to communicate the idea. Which is append a promise result to the piped observable keep it's original structure

[Observable<Actions>,Observable<State>,Observable<FromPromise>]

Joining a few dots here and taking a bit of a guess I would say the problem stems from TodosDB.getAll returning a Promise .

With a promise based function you want to lazily evaluate it, as such a function is executed immediately when it is called, unlike an observable based function which requires a subscription.

This is why the switchMap based solutions work, because the body of the switchMap is not evaluated until the source emits.

In your shortened version using withLatestFrom , there is no lazy evaluation, the getAll call is probably evaluated once and once only when the effect is set up.

You can use the defer operator to convert your promise based function to one that behaves more appropriately with the rxjs observable based operators.

withLatestFrom(defer(() => this.getAll())),  // use of defer
map(([[action, state], todos]) => [action, state, todos]),  // refine the shape of the data to your requirements
...

Stackblitz: https://stackblitz.com/edit/angular-ivy-qkwqyw?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fapp.component.html

Note: The concatLatestFrom ngrx operator also looks like it may be of use but I couldn't get it to work how I wanted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM