I want to detect when mousedown
is being fired for longer than 500ms, if so - do something. My attempt:
const button = document.querySelector('button')
const stream = Rx.Observable.fromEvent(button, 'mousedown')
const mouseUp$ = Rx.Observable.fromEvent(button, 'mouseup')
stream.delay(500).takeUntil(mouseUp$).subscribe(() => console.log(1))
It works but only the first time it runs. Then, the stream is cancelled due to takeUntil
operator. How to make it work everytime?
DEMO
Start a TimerObservable
for 500ms on every mouseDown$
event. If mouseUp$
get's fired within 500ms unsubscribe
from TimerObservable
.
const button = document.querySelector('button')
const mouseDown$ = Rx.Observable.fromEvent(button, 'mousedown')
const mouseUp$ = Rx.Observable.fromEvent(button, 'mouseup')
const stream$ = mouseDown$.switchMap(() => Rx.Observable.TimerObservable(500).takeUntil(mouseUp$));
stream$.subscribe(() => console.log('Only Fired after 500ms'))
RxJS >= 6.0.0
import { switchMap, takeUntil } from 'rxjs/operators';
import { timer, fromEvent } from 'rxjs';
const button = document.querySelector('button')
const mouseDown$ = fromEvent(button, 'mousedown')
const mouseUp$ = fromEvent(button, 'mouseup')
const stream$ = mouseDown$.pipe(
switchMap(() => timer(500).pipe(takeUntil(mouseUp$)))
);
stream$.subscribe(() => console.log('Only Fired after 500ms'))
Example of directive for mouse hold:
@Directive({ selector: "[appMouseHold]" })
export class MouseHoldDirective implements OnInit, OnDestroy {
@Input() set appMouseHold(tick: string | number) {
if (typeof tick === 'string') {
tick = parseInt(tick, 10);
}
this.tick = tick || 500;
}
private tick: number;
private readonly _stop = new Subject<void>();
private readonly _start = new Subject<void>();
private subscription: Subscription;
@Output() mousehold = new EventEmitter<number>();
@Output() mouseholdstart = new EventEmitter<void>();
@Output() mouseholdend = new EventEmitter<void>();
ngOnInit() {
this.subscription = this._start
.pipe(
tap(() => this.mouseholdstart.emit()),
switchMap(() =>
timer(500, this.tick).pipe(
takeUntil(this._stop.pipe(tap(() => this.mouseholdend.emit())))
)
)
)
.subscribe((tick) => {
this.mousehold.emit(tick);
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
@HostListener("mousedown", ["$event"])
onMouseDown($event) {
if ($event.button === 0) {
this._start.next();
}
}
@HostListener("mouseup")
onMouseUp() {
this._stop.next();
}
}
See Stackblitz
For non-angular usage you can simply replace @HostListener
handlers with fromEvent()
observables
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With