How to disable an event in RxJS?

I am trying to determine if a mousedown event persists for a period of time before mouseup .

I use timeout () in an Observable created with fromEvent() to do this, but a timeout returns both Observables.

Below, a stream subscription returns an event if mousedown starts within 1 second, but also returns 1.

 var mousedown = Rx.Observable.fromEvent(target, 'mousedown'); var stream = mousedown.timeout(1000, Rx.Observable.return(1)); var sub = stream.subscribe( function (x) { console.log('Next: '+x); }, function (err) { console.log('Err: '+err); }, function () { console.log('Complete'); } ); 

However, this works as expected:

 var source = Rx.Observable.return(42) .delay(200) .timeout(1000, Rx.Observable.return(1)); 

I want this code to work:

 var mousedown = Rx.Observable.fromEvent(target, 'mousedown'); var mouseup = Rx.Observable.fromEvent(target, 'mouseup'); var clickhold = mousedown .flatMap(function (){ return mouseup.timeout(1000, Rx.Observable.return('hold')); }) .filter(function (x) { return x === 'hold'; }); clickhold.subscribe( function (x) { console.log('Next: '+x); }, function (err) { console.log('Err: '+err); }, function () { console.log('Complete'); } ); 
+1
source share
2 answers

Instead of timeout I used delay and takeUntil :

 var target, mousedown, mouseup; target = document.querySelector('input'); mousedown = Rx.Observable.fromEvent(target, 'mousedown'); mouseup = Rx.Observable.fromEvent(target, 'mouseup'); var clickhold = mousedown .flatMap(function(){ // Triggered instantly after mousedown event. return Rx.Observable .return('hold') .delay(1000) // Discards the return value if by the time .delay() is complete // mouseup event has been already completed. .takeUntil(mouseup); }); clickhold.subscribe( function (x) { console.log('Next: ' + x); }, function (err) { console.log('Err: ' + err); }, function () { console.log('Complete'); } ); 
 <script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script> <input type='button' value='Button' /> 
+5
source

You came up with a great solution on your own. Here is what I would change:

  • Extract the internal observable ( timer(...).takeUntil(...).select(...) ) from flatMap so that it is not redistributed for each mouse.

Are you alright. For my use, I usually save the original mousedown event and use it instead of 'hold' . This requires returnValue and delay instead of timer and select .

 var target, mousedown, mouseup; target = document.querySelector('input'); mousedown = Rx.Observable.fromEvent(target, 'mousedown'); mouseup = Rx.Observable.fromEvent(target, 'mouseup'); var clickhold = mousedown .flatMap(function (e) { return Rx.Observable .return(e) .delay(1000) .takeUntil(mouseup); }); clickhold.subscribe(function (x) { console.log('onNext: ', x); }); 
 <script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script> <input type='button' value='Button' /> 

Or, for a completely different approach ...

 var Observable = Rx.Observable, fromEvent = Observable.fromEvent.bind(Observable, target), holdDelay = Observable.empty().delay(1000); Observable .merge( [ fromEvent('mouseup') .map(empty), fromEvent('mousedown') .map(Observable.returnValue) .map(holdDelay.concat.bind(holdDelay)) ] ) .switchLatest(); 

Ok, so weird. I really just give it as food, though, and show that this can be done in several ways.

+1
source

Source: https://habr.com/ru/post/1242682/


All Articles