Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJS observable which emits both previous and current value starting from first emission

I have a BehaviorSubject which emits JavaScript objects periodically. I want to construct another observable which will emit both previous and current values of the underlying observable in order to compare two objects and determine the delta.

The pairwise() or bufferCount(2, 1) operators are looking like a good fit, but they start emitting only after buffer is filled, but I require this observable to start emitting from the first event of the underlying observable.

subject.someBufferingOperator()
    .subscribe([previousValue, currentValue] => {
        /** Do something */
    })
;

On first emission the previousValue could be just null.

Is there some built-in operators that I can use to achieve the desired result?

like image 919
Slava Fomin II Avatar asked Apr 27 '18 09:04

Slava Fomin II


People also ask

What is pairwise in RxJS?

pairwiselinkGroups pairs of consecutive emissions together and emits them as an array of two values.

What RxJS type is used to produce values for multiple observers?

Subjectlink. What is a Subject? An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers.

What is pipe and map in RxJS?

Note: pipe() is a function/method that is used to chain multiple RxJS operators while map() and filter() are operators that operate and transform the values of an Observable (sequence of values). They are similar to the map() and filter() methods of JavaScript arrays.


3 Answers

Actually, it was as easy as pairing pairwise() with startWith() operators:

subject     .startWith(null) // emitting first empty value to fill-in the buffer     .pairwise()     .subscribe([previousValue, currentValue] => {         if (null === previousValue) {             console.log('Probably first emission...');         }     }) ; 
like image 75
Slava Fomin II Avatar answered Oct 06 '22 15:10

Slava Fomin II


Here's the snippet for rxjs 6+

subject     .pipe(        startWith(undefined),        pairwise()     )     .subscribe(([previousValue, currentValue]) => {         /** Do something */     }); 

The value in startWith() should be undefined because there is no value. Typically null is defined as "we have a value and this value is empty".

like image 44
Christoph Lütjen Avatar answered Oct 06 '22 16:10

Christoph Lütjen


Here's a simple operator:

function withPreviousItem<T>(): OperatorFunction<
  T,
  {
    previous?: T;
    current: T;
  }
> {
  return pipe(
      startWith(undefined),
      pairwise(),
      map(([previous, current]) => ({
        previous,
        current: current!
      }))
    );
}

The nice thing about this is that the result has meaningful property names and correct types:

  • previous is T | undefined
  • current is T (not T | null)

Stackblitz example

like image 41
TmTron Avatar answered Oct 06 '22 17:10

TmTron