window resize with observables in typescript

by Stefan Jelner

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.7/Rx.min.js"></script>
<div id="result"></div>

SCSS

body::before {
  content: 'xs';
  display: none;
  
  @media screen and (min-width: 480px) {
    content: 's';
  }
  
  @media screen and (min-width: 768px) {
    content: 'm';
  }
  
  @media screen and (min-width: 1024px) {
    content: 'l';
  }
  
  @media screen and (min-width: 1280px) {
    content: 'xl';
  }
}

TypeScript

class BreakpointChangeService {
	private breakpointChange$: BehaviorSubject<string>;
	
	constructor(): BehaviorSubject<string> {
		// initialize BehaviorSubject with the current content of the ::before pseudo element
		this.breakpointChange$ = new Rx.BehaviorSubject(this.getBreakpoint());
		
		// observe the window resize event, throttle it and combine it with the BehaviorSubject
		Rx.Observable
			.fromEvent(window, 'resize')
			.throttleTime(0, Rx.Scheduler.animationFrame)
			.withLatestFrom(this.breakpointChange$)
			.subscribe(this.update.bind(this))
		;
	
		return this.breakpointChange$;
	}
	
	// method to get the content of the ::before pseudo element
	private getBreakpoint(): string {
		// see https://www.lullabot.com/articles/importing-css-breakpoints-into-javascript
		return window.getComputedStyle(document.body, ':before').getPropertyValue('content').replace(/[\"\']/g, '');
	}
  
	private update(_, recent): void {
		var current = this.getBreakpoint();
		if(recent !== current) { this.breakpointChange$.next(current); }
	}
}

// if the breakpoint changes, react on it
var $result = document.getElementById('result');
new BreakpointChangeService().subscribe(breakpoint => {
	$result.innerHTML = Date.now()+': '+breakpoint;
});