admin管理员组

文章数量:1410717

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();

本文标签: javascriptHow to use combineLatest with filter in certain observableStack Overflow