最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to use combineLatest with filter in certain observable? - Stack Overflow

programmeradmin5浏览0评论

This is a simplification of a plex case, where some observables in array could be filtered if the values are not valid. The problem is that the filtered observable is not allowing to the other plete the bine. What operator or approach could handle this case allowing the valid data log in the subscription?

// RxJS v6+
import { fromEvent, bineLatest, of } from 'rxjs';
import { mapTo, startWith, scan, tap, map, filter } from 'rxjs/operators';

const userData$ = [
   of({ name: 'Joseph', age: 23}), 
   of({ name: 'Mario', age: 33}), 
   of({ name: 'Robert', age: 24}), 
   of({ name: 'Alonso', age: 25})
];

const names = ['Joseph', 'Mario', 'Robert', 'Alonso'];

bineLatest(
  names.map((name, i) => {
     return userData$[i].pipe(
         map(({name, age})=> { return{ name, age: age * 2} }),
         filter(({age}) => age < 67),
         map(({name, age})=> { return{ name: name.toLocaleUpperCase(), age} }),
     )
 })
)
   .pipe(
     tap(console.log),
   )
   .subscribe();

Sample in stackblitz

If we change the value to 67 all the observables will show the data.

This is a simplification of a plex case, where some observables in array could be filtered if the values are not valid. The problem is that the filtered observable is not allowing to the other plete the bine. What operator or approach could handle this case allowing the valid data log in the subscription?

// RxJS v6+
import { fromEvent, bineLatest, of } from 'rxjs';
import { mapTo, startWith, scan, tap, map, filter } from 'rxjs/operators';

const userData$ = [
   of({ name: 'Joseph', age: 23}), 
   of({ name: 'Mario', age: 33}), 
   of({ name: 'Robert', age: 24}), 
   of({ name: 'Alonso', age: 25})
];

const names = ['Joseph', 'Mario', 'Robert', 'Alonso'];

bineLatest(
  names.map((name, i) => {
     return userData$[i].pipe(
         map(({name, age})=> { return{ name, age: age * 2} }),
         filter(({age}) => age < 67),
         map(({name, age})=> { return{ name: name.toLocaleUpperCase(), age} }),
     )
 })
)
   .pipe(
     tap(console.log),
   )
   .subscribe();

Sample in stackblitz

If we change the value to 67 all the observables will show the data.

Share Improve this question asked Apr 23, 2020 at 5:20 TabaresTabares 4,3455 gold badges44 silver badges52 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

A typical problem with bineLatest is that it requires all source Observables to emit at least once so if you use filter to discard its only value then bineLatest will never emit anything.

An easy solution is to make sure it always emits with defaultIfEmpty:

bineLatest(
  names.map((name, i) => {
    return userData$[i].pipe(
      map(({name, age})=> { return { name, age: age * 2} }),
      filter(({age}) => age < 66),
      map(({name, age})=> { return { name: name.toLocaleUpperCase(), age} }),
      defaultIfEmpty(null),
    )
  })
)

Live demo: https://stackblitz./edit/typescript-rsffbs?file=index.ts

If your real use-case uses other source Observable than of() that doesn't plete immediatelly you might want to use startWith instead.

You can replace bineLatest with from as bineLatest won't emit if either one of the item in stream array doesn't emit

const userData$ = [
  { name: 'Joseph', age: 23 },
  { name: 'Mario', age: 33 },
  { name: 'Robert', age: 24 },
  { name: 'Alonso', age: 25 }
];

const names = ['Joseph', 'Mario', 'Robert', 'Alonso'];

from(
  userData$
)
  .pipe(
    map(({ name, age }) => { return { name, age: age * 2 } }),
    filter(({ age }) => age < 66),
    map(({ name, age }) => { return { name: name.toLocaleUpperCase(), age } }),
    tap(console.log),
  )
  .subscribe();
发布评论

评论列表(0)

  1. 暂无评论