Kai Sellgren
Kai Sellgren

Reputation: 30212

How to continuously sample data based on clicks in RxJS?

I have an observable with interesting data that changes over time (BehaviorSubject):

const obs = ...

Then I have a click action (Subject which gets called .next() upon button press):

const clickAction = ...

I wish to do this:

obs.pipe(sample(clickAction)).subscribe(data => console.log(data))

The problem I have is this: when I click my button multiple times in a row, it only logs the message once to the console. If obs changes, then clicking again will once again log to the console.

Expected behavior: the data (whether it has changed or not) should also be logged every time I click the button.

I thought sample was supposed to do this, but I reckon there must be a better way to do this?

Upvotes: 1

Views: 62

Answers (2)

Kai Sellgren
Kai Sellgren

Reputation: 30212

I ended up implementing this:

export function upon<T>(notifier: Observable<any>): MonoTypeOperatorFunction<T> {
  return (source: Observable<T>) => {
    const latest = withLatestFrom(source)(notifier)
    const mapper = map(([, source]: [any, T]) => source)
    return mapper(latest)
  }
}

Which can be used like so: obs.pipe(upon(clickAction))

Upvotes: 1

frido
frido

Reputation: 14109

sample isn't working in your case because:

sample looks at the source Observable and emits whichever value it has most recently emitted since the previous sampling, unless the source has not emitted anything since the previous sampling.


withLatestFrom

Use withLatestFrom to combine click events with the latest emitted value from your source observable.

clickAction.pipe(
  withLatestFrom(obs),
  map(([notifier, source]) => source)
).subscribe(console.log)

https://stackblitz.com/edit/typescript-uxizci

Upvotes: 1

Related Questions