ohadinho
ohadinho

Reputation: 7144

Cancel an observable created with "fromEvent" and switch to a new one

My goal is to emit "hi again" in 1 second interval until a key is pressed and continue whenever there is a mouse click. Here is my code:

import { of, fromEvent, interval } from 'rxjs'; 
import { map, tap, takeUntil,take, repeatWhen, shareReplay, switchMap , takeLast} from 'rxjs/operators';

const fromKeyUp$ = fromEvent(window, 'keyup').pipe(tap(_=> console.log('keyup')));

const fromMouseUp$ = fromEvent(window, 'mouseup').pipe(tap(_=> console.log('mouseup')));

const source = interval(1000).pipe(tap(_ => {
  console.log('hi again');
}), takeUntil(fromKeyUp$), repeatWhen(() => fromMouseUp$));

source.subscribe();

The problem is that when there are too many mouse clicks => "hi again" emits more times than usual.

I've tried to use switchMap to cancel previous mouseup's like:

const fromMouseUp$ = fromEvent(window, 'mouseup').pipe(switchMap(() => tap(_=> console.log('mouseup'))));

but it didn't work as tap is not meant for creation.

Any ideas ?

Upvotes: 2

Views: 1396

Answers (2)

Fan Cheung
Fan Cheung

Reputation: 11380

The below code will toggle value through by mouseup or stopped by keyup, you can put your handling logic inside mergeMap

const fromKeyUp$ = fromEvent(window, 'keyup').pipe(tap(_=> console.log('keyup')),mapTo(false));

const fromMouseUp$ = fromEvent(window, 'mouseup').pipe(tap(_=> console.log('mouseup')),mapTo(true));

const timeInterval=interval(1000).pipe(
  tap(_ => {
  console.log('hi again');
}))

const source=combineLatest(timeInterval,merge(fromMouseUp$,fromKeyUp$).pipe(startWith(true))
).pipe(
   mergeMap(([value,through])=>through? 
     of(value):never()),distinctUntilChanged() 
 )

source.subscribe(console.log);

another simplier alternative with windowToggle

interval(2000).pipe(
  windowToggle(fromMouseUp$.pipe(startWith(true)),()=>fromKeyUp$),
  switchMap(obs=>obs)
).subscribe(console.log)

both solution won't interrupt the source interval

Upvotes: 1

martin
martin

Reputation: 96969

I think you can just reorder the operators and use switchMap to cancel the previous interval:

fromMouseUp$.pipe(
  startWith(null),
  switchMap(() => interval(1000).pipe(
    takeUntil(fromKeyUp$),
  )),
).subscribe();

Upvotes: 3

Related Questions