Skip to content

Instantly share code, notes, and snippets.

@fragsalat
Created March 11, 2019 09:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fragsalat/f9039e422ae1cbdec171c9d7f02f8462 to your computer and use it in GitHub Desktop.
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.
@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