Last active
April 26, 2016 10:04
-
-
Save marlun78/6381a526216f353f2ee38444df02d6b5 to your computer and use it in GitHub Desktop.
Fiddling around with some kind of observable values
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
/** | |
* An ObservableValue are like events for values. One important difference from | |
* events is that you are guaranteed to always get the current value when you | |
* subscribe. So there is no chance you subscribe “too late”. It will also | |
* pass you the new value together withthe old value. | |
* ObservableValue are similar to Angular’s `Scope.$watch`. | |
* | |
* http://jsbin.com/hokagosaru/edit?js,console | |
*/ | |
// TODO: Create repo | |
// TODO: Write unit tests | |
// Create an observable value and assign it 1. | |
const value = new ObservableValue(1); | |
// The Observer object can be given to any third party that wants to | |
// observe the changes on this value. | |
const observer = value.observer; | |
// Call subscribe to get notified when the value changes. The handler will | |
// always get called immediately with the current value and undefined. The | |
// subscribe method returns an unsubscribe function. | |
const unsubscribe = observer.subscribe((newValue, oldValue) => | |
console.log(['change', newValue, oldValue])); | |
// To change the value, call set. | |
value.set(2); | |
// To stop listening for changes, call the unsubscribe function returned from | |
// the subscribe call, or call unsubscribe on the observer passing in the | |
// original handler. Eg. `observer.unsubscribe(handler)`. | |
unsubscribe(); | |
// Setting the value again after calling unsubscribe, should not trigger the | |
// handler. | |
value.set(3); | |
// To get the current value from the observable value, call get. | |
console.log(value.get()); | |
/** | |
* ObservableValue rough implementation. | |
*/ | |
ObservableValue.create = (defaultValue) => new ObservableValue(defaultValue); | |
export function ObservableValue(defaultValue) { | |
if (!(this instanceof ObservableValue)) { | |
return new ObservableValue(defaultValue); | |
} | |
let currentValue = defaultValue; | |
const handlers = []; | |
const observer = { | |
subscribe(handler) { | |
if (!isFunction(handler)) { | |
throw new TypeErro(handlerMustBeAFunction(handler)); | |
} | |
handlers.push(handler); | |
handler(currentValue); | |
return () => this.unsubscribe(handler); | |
}, | |
unsubscribe(handler) { | |
if (!isFunction(handler)) { | |
throw new TypeErro(handlerMustBeAFunction(handler)); | |
} | |
const index = handlers.indexOf(handler); | |
if (index !== -1) { | |
handlers.splice(index, 1); | |
} | |
} | |
}; | |
Object.defineProperty(this, 'observer', { | |
get() { return observer; }, | |
set() { throw new Error('The observer is readonly'); } | |
}); | |
this.get = () => currentValue; | |
this.set = (newValue) => { | |
handlers.forEach((handler) => handler(newValue, currentValue)); | |
currentValue = newValue; | |
}; | |
function isFunction(value) { | |
return typeof value === 'function'; | |
} | |
function handlerMustBeAFunction(handler) { | |
return `Handler must be a function, got ${typeof handler}`; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment