user4676340
user4676340

Reputation:

Cancel a delay if same observable emits

const observable = new rxjs.BehaviorSubject(0);

observable.subscribe(v => console.log(v));

rxjs
  .of(1)
  .pipe(rxjs.operators.delay(500))
  .subscribe(v => observable.next(v));
  
observable.next(2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.1/rxjs.umd.js"></script>

As you can see, the observable above emits 3 values in order : 0, 2, 1.

Would it be possible to cancel (or ignore) the value "1" when the value "2" is emitted ? (Without closing the subscription)

Upvotes: 1

Views: 3244

Answers (3)

kos
kos

Reputation: 5364

Seems like you need to switchMap from your source and apply a delay inside of it.

switchMap(value =>
 of(value).pipe(delay(50))
)

An illustration and a playground for switchMap with a delay:

delay with a switchMap

And heres a snippet:

const {Subject, of} = rxjs;
const {switchMap, delay} = rxjs.operators;

const subject = new Subject(0);

subject
  .pipe(
     switchMap(value =>
       // switchMap to a delayed value
       of(value).pipe(delay(500))
     )
  )
  .subscribe(v => console.log(v));

// immediately emit 0
subject.next(0);

// emit 1 in 1 sec
setTimeout(()=>{
  subject.next(1);
}, 1000)

// emit 2 in 1.2 sec
setTimeout(()=>{
  subject.next(2);
}, 1200)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.1/rxjs.umd.js"></script>

Heres an example with mousehover

const {fromEvent, merge, of, EMPTY} = rxjs;
const {switchMap, delay, mapTo} = rxjs.operators;

const button = document.getElementById('pane');
const mouseOver$ = fromEvent(button, 'mouseover').pipe(
  mapTo(true)
);

const mouseOut$ = fromEvent(button, 'mouseout').pipe(
  mapTo(false)
);

merge(mouseOver$, mouseOut$)
  .pipe(
     switchMap(value => {
       if (!value) { return EMPTY; }
       return of('mouse is over').pipe(delay(500))
     })
  )
  .subscribe(v => console.log(v));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.1/rxjs.umd.js"></script>

<style>
#pane{
  margin: 1rem;
  display: inline-block;
  width: 5rem;
  height: 5rem;
  background: rebeccapurple;
}</style>

<div id="pane"><div>

Hope this helps

Upvotes: 7

n00dl3
n00dl3

Reputation: 21584

The operator you are looking for is debounceTime :

debounceTime

Emits a value from the source Observable only after a particular time span has passed without another source emission.

source

rxjs.interval(100)
  .pipe(
    rxjs.operators.take(10),
    rxjs.operators.debounceTime(500)
  )
  .subscribe((v)=>{
    console.log(v);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.1/rxjs.umd.js"></script>

Upvotes: 4

Lagistos
Lagistos

Reputation: 3978

So for mouse enter and leave you are looking for debounceTime for example:

const observable = new BehaviorSubject(0);
observable
  .pipe(debounceTime(500))
 .subscribe(console.log);

observable.next(1),
observable.next(2);
setTimeout(() => observable.next(3) , 1000)

In this example that will print 2 and after one seconed 3. After each emitited value the observable wait for 500 ms and if there are no new value it will print in the subscribe else it will cancel the last one and start this proccess again, hope this will solve your problem

Upvotes: 1

Related Questions