Created
June 14, 2016 12:57
-
-
Save far-blue/20e368e175b05429a054d011f02830ad to your computer and use it in GitHub Desktop.
First attempt at creating a custom observable for Knockout to wrap a NestedTypes model instance attribute efficiently.
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
function modelAttributeObservable(model, attribute) | |
{ | |
// Check the attribute exists | |
if (!(attribute in model)) { | |
throw new ReferenceError(attribute + ' is not an attribute of the supplied model'); | |
} | |
// Setup the attribute observable cache | |
model._koObservables || (model._koObservables = {}); | |
// If we already have a cached observable then just return it | |
if (attribute in model._koObservables) { | |
return model._koObservables[attribute]; | |
} | |
// Create our observable getter/setter function | |
function observableAttribute() | |
{ | |
if (arguments.length > 0) { | |
observableAttribute.valueWillMutate(); | |
model[attribute] = arguments[0]; | |
return this; | |
} else { | |
// The caller only needs to be notified of changes if they did a "read" operation | |
ko.computedContext.oc(observableAttribute); | |
return observableAttribute.peek(); | |
} | |
} | |
// Create a function to fetch the attribute value that | |
// is in the correct context so it has access to the model. | |
observableAttribute.peek = function() { | |
return model[attribute]; | |
} | |
// Register to listen to change events on the model attribute | |
model.on('change:'+attribute, function() { | |
observableAttribute.valueHasMutated(); | |
}); | |
// Initialise the observableAttribute as a subscribable | |
// Then override the prototype to make it a subclass | |
ko.subscribable.call(observableAttribute); | |
observableAttribute.__proto__ = observableAttribute_fn; | |
// setup the deferred update extender if needed | |
ko.options['deferUpdates'] && ko.extenders['deferred'](observableAttribute, true); | |
// Cache the observableAttribute function and return it | |
return (model._koObservables[attribute] = observableAttribute); | |
}; | |
// Setup the prototype for the observableAttribute as a subclass of subscribable | |
observableAttribute_fn = { | |
__proto__: ko.subscribable['fn'], | |
valueHasMutated: function () { this.notifySubscribers(this.peek()); }, | |
valueWillMutate: function () { this.notifySubscribers(this.peek(), 'beforeChange');}, | |
// Make KO treat the observableAttribute function as an observable | |
'__ko_proto__': ko.observable | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment