Created
July 15, 2016 13:18
-
-
Save albulescu/3f1e2b9cc3bb78a06dbbafff9bc2723d to your computer and use it in GitHub Desktop.
Angular 2 style change watcher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const watcher = new StyleChangeWatcher(); | |
watcher.watch(element, ["width"]); | |
watcher.observer.subscribe((event:StyleChangeEvent) => { | |
console.log('Element:', event.element); | |
console.log('Change:', event.change.property,':', event.change.previous, '=>', event.change.current); | |
}); | |
// source | |
import { Injectable, EventEmitter } from '@angular/core'; | |
export class StyleChangeEvent { | |
constructor( | |
public element:HTMLElement, | |
public change:Change) | |
{ | |
} | |
} | |
export class Change { | |
constructor( | |
public property:string, | |
public previous:string, | |
public current:string | |
){} | |
} | |
@Injectable() | |
export class StyleChangeWatcher { | |
private emitter:EventEmitter<StyleChangeEvent>; | |
private elements:any[] = []; | |
private checkFn:EventListener; | |
private running:boolean = false; | |
constructor() { | |
this.emitter = new EventEmitter<StyleChangeEvent>(); | |
this.checkFn = this.check.bind(this); | |
} | |
get observer():EventEmitter<StyleChangeEvent> { | |
return this.emitter; | |
} | |
/** | |
* Start watching element style changes | |
*/ | |
watch( element:HTMLElement, props:string[] ) { | |
this.elements.push({ | |
element: element, | |
props: props, | |
computed: Object.assign({},window.getComputedStyle(element, null)) | |
}); | |
this.start(); | |
} | |
/** | |
* Unwatch an element from style props change | |
*/ | |
unwatch( element:HTMLElement, props:string[] ):boolean { | |
for (var index = 0; index < this.elements.length; index++) { | |
let current = this.elements[index]; | |
if ( current.element === element && current.props === props ) { | |
if (this.elements.length === 0) { | |
this.stop(); | |
} | |
this.elements.splice(index, 1); | |
return true; | |
} | |
} | |
return false; | |
} | |
start():void { | |
if (this.running) { | |
return; | |
} | |
this.running = true; | |
window.addEventListener('resize', this.checkFn); | |
} | |
stop():void { | |
if (!this.running) { | |
return; | |
} | |
this.running = false; | |
window.removeEventListener('resize', this.checkFn); | |
} | |
private checkElement(element:HTMLElement, props:string[], computed:any):Change[] { | |
let changes:Change[] = []; | |
let actual:any = window.getComputedStyle(element,null); | |
for(let name of props) { | |
if ( computed[name] != actual[name] ) { | |
changes.push(new Change(name, computed[name], actual[name])); | |
computed[name] = actual[name]; | |
} | |
} | |
return changes; | |
} | |
private check(evt: Event):void { | |
for(let current of this.elements) { | |
let changes:Change[] = this.checkElement( current.element, current.props, current.computed ); | |
if (changes.length) { | |
for(let change of changes) { | |
this.emitter.next( | |
new StyleChangeEvent( | |
current.element, | |
change | |
) | |
); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment