Both Angular and Rxjs give you the ability to easily listen to events. Using Angualr's @HostListener() annotation allows a declarative binding while using Rxjs event binding allows for filtering, debouncing and throttling of events, to name a few.
The prefered way to bind to events in an Angular component is to use the @HostListener()
annotation. This provides a clean declarative binding from an event to a method, and best of all works without the need to access any browser specific APIs such as document
or window
. Avoiding direct browser DOM APIs becomes important if you want to use the Universal server-side rendering or run the applicaton in a WebWorker. Keeping your code open to either of these possibilities, even if you have no plan at the moment, allows you to take advantage of future optimizations.
Throttling Resize
You may ask, why do I need to listen to resize events?
You may not need to. As many of your UI elements as possible should respond to form factor changes through CSS cues rather than scripted cues. Mobile and Tablet devices don't have any real stories where the viewport changes sizes that aren't handled by the deviceorientation
event. Their are probably some edge cases like split screen and some virtual keyboards pushing up on the browser window.
Their may be some exceptions to this where you will need to script the responsiveness. For example, you may have a menu that is pinned open on desktop form factor, pinned in a minimized mode on tablets in landscape mode, and hidden behind a hamburger menu on portrait tablets and phones.
Even with this scenario a valid situation where a user is resizing, not rotating, the browser window is at best an edge case.
In reality the use case is a developer story. As a developer you want to be sure that your UI behaves at every width between the smallest acceptable width to the largest. You want to be able to stretch your responsive browser developer tools from tiny to extra-large and ensure that the app will display correctly for every pixel width.
private resizeObservable = Observable.fromEvent(
window,
'resize'
).throttleTime(200);
Nice and clean. But there is a problem with this. We are accessing the DOM window
directly. We could wrap this in a try/catch, or inject a window into our component that gets replaced with a fake if we run on the server, but then if we decide to run in a WebWorker we are out of luck and will need to replace this code.
The Solution
We can use the Rjxs throttle method in conjunction with Angular's @HostLister()
decorator annotations.
In our example below we create a Subject of type number named resizeSubject
. We will call the next()
method on resizeSubject
in our event handler.
export class AppComponent implements OnInit {
private resizeSubject = new Subject<number>();
private resizeObservable = this.resizeSubject.asObservable()
.throttleTime(200);
@HostListener('window:resize', ['$event.target.innerWidth'])
onResize(width: number) {
this.resizeSubject.next(width);
}
ngOnInit() {
this.resizeObservable.subscribe(x =>
this.doSomethingWithThrottledEvent(x));
}
private doSomethingWithThrottledEvent(width: number) {
// . . .
}
}
Top comments (0)