Reputation: 79
I am using mouseenter and mouseleave events to handle sidenav opening and closing in my app. I would like to add a bit of debounce to these events, because right now if you hover the container with these events fast, these events are being called a lot of times and I'm getting weird behavior with my sidenav. How can I add debounce to these events ? Is it event possible ?
Upvotes: 3
Views: 11244
Reputation: 9469
You can create a directive which you can add to your input then. In this example I debounce click event, but you can easily accomodate it to any other event.
import { Directive, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
@Directive({
selector: '[debounceClick]'
})
export class DebounceClickDirective implements OnInit, OnDestroy {
@Input()
public debounceClickTime = 500;
@Output()
public debounceClick = new EventEmitter();
private clicks = new Subject();
private subscription: Subscription;
constructor() { }
public ngOnInit() {
this.subscription = this.clicks.pipe(debounceTime(this.debounceClickTime)).subscribe((e: Event) =>
this.debounceClick.emit(e));
}
public ngOnDestroy() {
this.subscription.unsubscribe();
}
@HostListener('click', ['$event'])
public clickEvent(event: Event) {
event.preventDefault();
event.stopPropagation();
this.clicks.next(event);
}
}
And use it in your HTML in a following way:
<input type="text" (debounceClick)="yourMethod()" debounceClickTime="1000" />
debounceClickTime
is optional and if you do not use it, it debounces by default in 500ms.
Upvotes: 1
Reputation: 1880
RXJS has a function FromEvent which convert event to Stream u have to create two streams ,one on enter and other on leave
I think with debounceTime u should use distinctUntilChanged as well. otherwise it will emit true true, or false false , but u need true false or false true sequence
@ViewChild('sizeMenu')
set SizeMenu(sizeMenu: ElementRef) {
let mouseEnter$ = fromEvent(sizeMenu.nativeElement, 'mouseenter').pipe(
mapTo(true));
let mouseLeave$ = fromEvent(sizeMenu.nativeElement, 'mouseleave').pipe(
mapTo(false));
this.mouseEvents$ = mouseLeave$.pipe(merge(mouseEnter$), debounceTime(this.DebounceTime), distinctUntilChanged());
};
this is example on stackblitz
Upvotes: 1
Reputation: 4228
Add a template reference variable on your button :
<button #button>Click me</button>
Reference it inside your component using @ViewChild
@ViewChild('button') button: ElementRef;
Use fromEvent from rxjs to listen to the click event and use the debounceTime operator :
ngAfterViewInit() {
fromEvent(this.button.nativeElement, 'click').pipe(
debounceTime(2000) // 2 seconds
).subscribe(() => {
// do whatever
});
}
Upvotes: 6