Reputation: 1494
I am working on an Angular project where a directive needs to react to mouseenter
and mouseleave
events. it needs to update the CSS of the host element where it is used.
Consider the contrived example below:
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[appMouseEvents]',
})
export class MouseEventsDirective {
constructor(private element: ElementRef) {
}
@HostListener('mouseEnter', ['$event'])
onMouseEnter() {
console.log('mouseenter');
}
@HostListener('mouseleave',['$event'])
onMouseLeave() {
console.log('mouseleave');
}
}
app.component.html
<hello name="{{ name }}"></hello>
<p appMouseEvents>
Hover Mouse over me
</p>
When I profile the application in Angular Dev tools, I see that these event cause Angular to trigger change detection which is not needed as only the CSS of host element is affected.
Is there a way to react to mouse event in the directive and not trigger change detection?
Here's a demo application: https://stackblitz.com/edit/angular-ivy-r6ln5w?file=src%2Fapp%2Fapp.component.ts
Upvotes: 1
Views: 1330
Reputation: 489
You may need to use NgZone to run code outside of Angular zone (scope) and thus prevent angular change detection https://angular.io/api/core/NgZone
Your directive will look something like this:
import { Directive, ElementRef, HostListener, NgZone } from '@angular/core';
@Directive({
selector: '[appMouseEvents]',
})
export class MouseEventsDirective {
constructor(private element: ElementRef, private zone: NgZone) {
this.zone.runOutsideAngular(() => {
this.element.nativeElement.addEventListener('mouseenter', (e) => {
// e.preventDefault();
// e.stopPropagation();
console.log('mouseenter');
});
});
this.zone.runOutsideAngular(() => {
this.element.nativeElement.addEventListener('mouseleave', (e) => {
// e.preventDefault();
// e.stopPropagation();
console.log('mouseleave');
});
});
}
}
Here is you stackblitz modified https://stackblitz.com/edit/angular-ivy-faavr3?file=src/app/mouse-events.directive.ts
Hope this helps.
Edit: Updated source code
https://stackblitz.com/edit/angular-ivy-qvyk2t?file=src%2Fapp%2Fmouse-events.directive.ts
Upvotes: 1
Reputation: 136144
Yes, event fired on DOM would be monkey patched by zone.js and it triggers a change detection.
I would suggest you to go here using native browser feature. Like use :hover
pseudo css class on host element.
:host:hover {
// CSS rules
}
Alternative way to fix it would be using this.zone.runOutsideAngular
as other suggested answer.
Upvotes: 1