Skip to content

Instantly share code, notes, and snippets.

@albulescu
Created July 15, 2016 13:18
Show Gist options
  • Save albulescu/3f1e2b9cc3bb78a06dbbafff9bc2723d to your computer and use it in GitHub Desktop.
Save albulescu/3f1e2b9cc3bb78a06dbbafff9bc2723d to your computer and use it in GitHub Desktop.
Angular 2 style change watcher
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