Created
March 11, 2019 09:58
-
-
Save fragsalat/f9039e422ae1cbdec171c9d7f02f8462 to your computer and use it in GitHub Desktop.
Observer based on aurelia expressions which triggers subscribers also when children and parents changed.
This file contains 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
@connectable() | |
@subscriberCollection() | |
export class DeepExpressionObserver { | |
constructor(scope, expression, observerLocator: ObserverLocator, lookupFunctions) { | |
this.scope = scope; | |
this.expression = expression; | |
this.observerLocator = observerLocator; | |
this.lookupFunctions = lookupFunctions; | |
} | |
getValue() { | |
return this.expression.evaluate(this.scope, this.lookupFunctions); | |
} | |
setValue(newValue) { | |
this.expression.assign(this.scope, newValue); | |
} | |
subscribe(context, callable) { | |
if (!this.hasSubscribers()) { | |
this.oldValue = this.expression.evaluate(this.scope, this.lookupFunctions); | |
this.expression.connect(this, this.scope); | |
// Observe children as the parent is considered to be changes as well when children changes | |
this.deepObserve(this.oldValue); | |
} | |
this.addSubscriber(context, callable); | |
if (arguments.length === 1 && context instanceof Function) { | |
return { | |
dispose: () => { | |
this.unsubscribe(context, callable); | |
} | |
}; | |
} | |
} | |
deepObserve(obj) { | |
if (typeof obj !== 'object') { | |
return; | |
} | |
Object.keys(obj).forEach(property => { | |
const observer = this.observerLocator.getObserver(obj, property); | |
observer.subscribe(newValue => { | |
// As the object itself didn't changed but a referenced property new and old value are equal | |
this.callSubscribers(this.oldValue, this.oldValue); | |
this.deepObserve(this.oldValue); | |
}); | |
if (typeof obj[property] === 'object') { | |
this.deepObserve(obj[property]); | |
} | |
}); | |
} | |
unsubscribe(context, callable) { | |
if (this.removeSubscriber(context, callable) && !this.hasSubscribers()) { | |
this.unobserve(true); | |
this.oldValue = undefined; | |
} | |
} | |
call() { | |
let newValue = this.expression.evaluate(this.scope, this.lookupFunctions); | |
let oldValue = this.oldValue; | |
if (newValue !== oldValue) { | |
this.oldValue = newValue; | |
this.callSubscribers(newValue, oldValue); | |
} | |
this._version++; | |
this.expression.connect(this, this.scope); | |
this.deepObserve(this.oldValue); | |
this.unobserve(false); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment