Detecting real time window size changes in Angular 4
I have been trying to build a responsive nav-bar and do not wish to use a media query, so I intend to use *ngIf
with the window size as a criterion.
But I have been facing a problem as I am unable to find any method or documentation on Angular 4 window size detection. I have also tried the JavaScript method, but it is not supported.
I have also tried the following:
constructor(platform: Platform) {
platform.ready().then((readySource) => {
console.log('Width: ' + platform.width());
console.log('Height: ' + platform.height());
});
}
...which was used in ionic.
And screen.availHeight
, but still no success.
Solution 1:
To get it on init
public innerWidth: any;
ngOnInit() {
this.innerWidth = window.innerWidth;
}
If you wanna keep it updated on resize:
@HostListener('window:resize', ['$event'])
onResize(event) {
this.innerWidth = window.innerWidth;
}
Solution 2:
If you want to react on certain breakpoints (e.g. do something if width is 768px or less), you can use BreakpointObserver
:
import { Component } from '@angular/core';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
constructor(
private breakpointObserver: BreakpointObserver,
) {
// detect screen size changes
this.breakpointObserver.observe([
"(max-width: 768px)"
]).subscribe((result: BreakpointState) => {
if (result.matches) {
// hide stuff
} else {
// show stuff
}
});
}
}
Solution 3:
This is an example of service which I use.
You can get the screen width by subscribing to screenWidth$
, or via screenWidth$.value
.
The same is for mediaBreakpoint$
( or mediaBreakpoint$.value
)
import {
Injectable,
OnDestroy,
} from '@angular/core';
import {
Subject,
BehaviorSubject,
fromEvent,
} from 'rxjs';
import {
takeUntil,
debounceTime,
} from 'rxjs/operators';
@Injectable()
export class ResponsiveService implements OnDestroy {
private _unsubscriber$: Subject<any> = new Subject();
public screenWidth$: BehaviorSubject<number> = new BehaviorSubject(null);
public mediaBreakpoint$: BehaviorSubject<string> = new BehaviorSubject(null);
constructor() {
this.init();
}
init() {
this._setScreenWidth(window.innerWidth);
this._setMediaBreakpoint(window.innerWidth);
fromEvent(window, 'resize')
.pipe(
debounceTime(1000),
takeUntil(this._unsubscriber$)
).subscribe((evt: any) => {
this._setScreenWidth(evt.target.innerWidth);
this._setMediaBreakpoint(evt.target.innerWidth);
});
}
ngOnDestroy() {
this._unsubscriber$.next();
this._unsubscriber$.complete();
}
private _setScreenWidth(width: number): void {
this.screenWidth$.next(width);
}
private _setMediaBreakpoint(width: number): void {
if (width < 576) {
this.mediaBreakpoint$.next('xs');
} else if (width >= 576 && width < 768) {
this.mediaBreakpoint$.next('sm');
} else if (width >= 768 && width < 992) {
this.mediaBreakpoint$.next('md');
} else if (width >= 992 && width < 1200) {
this.mediaBreakpoint$.next('lg');
} else if (width >= 1200 && width < 1600) {
this.mediaBreakpoint$.next('xl');
} else {
this.mediaBreakpoint$.next('xxl');
}
}
}
Hope this helps someone
Solution 4:
If you'd like you components to remain easily testable you should wrap the global window object in an Angular Service:
import { Injectable } from '@angular/core';
@Injectable()
export class WindowService {
get windowRef() {
return window;
}
}
You can then inject it like any other service:
constructor(
private windowService: WindowService
) { }
And consume...
ngOnInit() {
const width= this.windowService.windowRef.innerWidth;
}