I am implementing dragging functionality into an angular app: http://jsfiddle.net/Jjgmz/1/
Part of it, is to listen for mousemove
event on a document ob
1) Using @HostListener
(docs). This is the prefered method which should be enough most of the time.
import {Component, NgModule, HostListener} from '@angular/core'
@Component({
...
})
export class MyComponent {
@HostListener('document:mousemove', ['$event'])
onMouseMove(e) {
console.log(e);
}
..
}
2) Similar to the above, you can also use (document:event)="handler"
on any DOM element, but the above solution is prefered because the code is cleaner. By using this, it's not immediately obvious from the class that you have a global event listener, and you might add additional ones unnecessarily.
@Component({
selector: 'my-app',
template: `
<div (document:mousemove)="onMouseMove($event)" id="box"></div>
`,
})
export class MyComponent {
onMouseMove(e) {
console.log(e);
}
}
3) The Renderer
(docs) is a lower-level solution; useful when you do not want to clutter your code with methods, but deal with the even elsewhere, for example in a hook, as the following snippet shows. Be careful, though, as you still need to remove the event listener to prevent memory leaks; either do this when you know you won't need it anymore, or in the OnDestroy hook.
import { Component, Renderer2 } from '@angular/core';
@Component({
...
})
export class MyComponent {
globalListenFunc: Function;
constructor(private renderer: Renderer2) {}
ngOnInit() {
this.globalListenFunc = this.renderer.listen('document', 'mousemove', e => {
console.log(e);
});
}
ngOnDestroy() {
// remove listener
this.globalListenFunc();
}
}
4) Alternative of the first example is a host property, which is discouraged by the Angular Style Guide, since you now keep track of the function name in two places which can be very far apart physically in code. Prefer the first version whenever possible.
@Component({
...
host: {
'(document:mousemove)': 'onMouseMove($event)'
}
})
export class MyComponent {
onMouseMove(e) {
console.log(e);
}
}
5) A reactive way, which Angular embraces, is using Observable.fromEvent
. This gives you a benefit of all RxJS operators for transforming the stream before executing a function. Be careful, though, as you need to unsubscribe manually to avoid memory leaks (unless you subscribe directly in the template using async
pipe; this will handle unsubscription for you). Also don't forget to add-import the operator, as shown in the following snippet.
import { Subscription, fromEvent } from 'rxjs';
@Component({
...
})
export class MyComponent {
subscription: Subscription;
ngOnInit() {
this.subscription =
fromEvent(document, 'mousemove')
.subscribe(e => {
console.log(e);
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
6) Of course, document.addEventListener
is always a solution as well; but this is not an intended usage in Angular apps; you should choose different ways. Directly accessing DOM is discouraged as it breaks Angular's neat encapsulation of DOM manipulation. Also you could run into problems with Universal and SSR.