I need an operator like withLatestFrom, except it fires as soon as both Observables have emitted a value

Viewed 352

So withLatestFrom is very close to what I need, but it has a weird behavior. It only emits a value if the "master" emits AFTER the "slave". As shown in this Marble diagram:

--1----2-------2---- (source)
----a-------b------- (other1)
-------2a------2b--

I need an operator which behaves like this:

--1------2-------2---- (source)
----a---------b------- (other1)
----1a---2a------2b--

and this:

------1------2-------2---- (source)
--a--------------b------- (other1)
------1a-----2a------2b--

In other words, it basically needs to act like CombineLatest for the first emits, and then behave like withLatestFrom afterwards. How can I achieve this behavior?

3 Answers

I don't think there is an operator specific to that but try the snippet below.

Try this:

combineLatest(
  source,
  other1.pipe(
    take(1), // only take one emission, the take(1) might kill this observable and stop further emissions but give it a try
  )
).pipe(
  withLatestFrom(other1),
).subscribe(result => {
  console.log(result);
  const source = result[0][0]; // I am not sure how to destructure it but I suspect
  const other1 = result[1]; // result will be a 2d array in the form of
                               // [[source, firstEmissionOther1], other1]
  console.log(source); 
  console.log(other1);
})

You could try with the pairwise operator

combineLatest([master$, slave$])
  .pipe(
    startWith([null, null]),
    pairwise(),
    filter(([prev, curr]) => curr[0] !== prev[0]),
    map(([prev, curr]) => curr)
  )
  .subscribe(result => console.log(JSON.stringify(result)));

See the same on stackblitz https://stackblitz.com/edit/rxjs-4uyclu?file=index.ts

combineLatest with a distinct source stream.

One approach might be to use combineLatest and ignore emissions that don't origionate from the source. The typical caveats of JS object comparison do apply here so you may want to adjust your custom comparer function accordingly.

combineLatest(
  source$,
  latestFrom$
).pipe(
  distinctUntilChanged((prev, curr) => prev[0] === curr[0])
)
Related