Explain Codes LogoExplain Codes Logo

Angular window resize event

javascript
rxjs
angular
event-handling
Nikita BarsukovbyNikita Barsukov·Oct 31, 2024
TLDR

For quick window resize event capture in Angular, use @HostListener:

import { HostListener } from '@angular/core'; export class MyClass { @HostListener('window:resize', ['$event']) onResize(event) { // Your UI or logic reaction to new window dimensions console.log(`👀 I see new width: ${event.target.innerWidth}`); } }

This takes care of auto subscription and cleanup, adhering to Angular's component lifecycle.

Want to perform better like a sports car? Kick in some Racing exhaust system... err, RxJS:

import { fromEvent, throttleTime } from 'rxjs'; const resizeObservable = fromEvent(window, 'resize').pipe(throttleTime(1000)); resizeObservable.subscribe(event => { console.log(`Running faster with new width: ${event.target.innerWidth}`); });

This cruises your window resize events by throttling, enhancing your performance and preventing your app from overheating.

Mastering window resize with Angular and RxJS

Angular and RxJS offer several tricks to optimally handle resize events. Let's dive deeper into handling resize events like a JavaScript ninja.

Dialing the RxJS frequency down

Use RxJS to convert our resize event into an Observable, and add a throttle to keep events in control:

import { fromEvent } from 'rxjs'; import { throttleTime } from 'rxjs/operators'; @Component({...}) export class MyClass implements OnInit, OnDestroy { resizeObs; ngOnInit() { this.resizeObs = fromEvent(window, 'resize') .pipe(throttleTime(500)) // Emit once at most every half second .subscribe(event => this.onResize(event)); } onResize(event) { // Bruce Lee says: "Be like water, my friend." } ngOnDestroy() { this.resizeObs.unsubscribe(); // Don't forget to clean up! } }

The power of Angular CDK's ViewportRuler

Angular's ViewportRuler is like a Jedi Knight watching over the viewport and alerting on size changes:

import { ViewportRuler } from '@angular/cdk/scrolling'; @Component({...}) export class MyClass implements OnInit, OnDestroy { constructor(private viewportRuler: ViewportRuler) {} ngOnInit() { this.viewportRuler.change(500).subscribe(() => this.onViewportResize()); } onViewportResize() { // Call to action! Adjustments needed 🛠️ } ngOnDestroy() { // May the force be with you... } }

Listen to this Jedi Knight through this.viewportRuler.change(). This will be more efficient and cooler.

Centralize with a Resize Service

Make your life easier and cleaner by keeping all the resize logic in one place, in a Resize Service:

@Injectable({ providedIn: 'root' }) export class ResizeService { constructor(private ngZone: NgZone, private viewportRuler: ViewportRuler) {} get onResize$() { return this.ngZone.runOutsideAngular(() => this.viewportRuler.change().pipe( throttleTime(500), tap(() => this.ngZone.run(() => {})) ) ); } }

Utilize this service in your components for sightseeing the viewport:

@Component({...}) export class MyClass implements OnInit, OnDestroy { constructor(private resizeService: ResizeService) {} ngOnInit() { this.resizeService.onResize$.subscribe(() => this.onResize()); } onResize() { // It's morphin' time! } ngOnDestroy() { // Always remember: Cleanup after your morphing session } }

Playing nice with server-side rendering

Catering to SSR (Server-Side Rendering)

For Server-Side Rendering compatibility, avoid directly interacting with window. It's kinda shy and doesn't exist on server side:

import { PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @Component({...}) export class MyClass implements OnInit { constructor(@Inject(PLATFORM_ID) private platformId: Object) {} ngOnInit() { if (isPlatformBrowser(this.platformId)) { // Moving with the cool kids (aka browser APIs) } } }

Angular's EventManager to the rescue

Make your window resize events compatible with every habitat with Angular's EventManager:

import { EventManager } from '@angular/platform-browser'; constructor(private eventManager: EventManager) {} ngOnInit() { this.eventManager.addGlobalEventListener('window', 'resize', this.onResize.bind(this)); } onResize(event) { // Roll with the punches when dimensions change }

Caveats and pro-tips

Take care of memory leaks

Remember to leave no trace behind as you exit - unsubscribe your observables in ngOnDestroy:

ngOnDestroy() { this.resizeSubscription.unsubscribe(); // Leave it cleaner than you found it }

Mind your inline event binding

Although inline (window:resize)="onResize($event)" binding is tempting with its simplicity, it's like a sports car without a racing driver—less performant and trickier to control.

Stay updated with Angular issues

Being aware of Angular issues like #13248 can make your resize event journey smoother.

Embrace the power of imperative event handling

Like a Jedi, you can gain more control with the imperative approach by managing DOM events directly— it's a more 'forceful' strategy with better performance.