Created
February 10, 2012 21:51
-
-
Save domenic/1793211 to your computer and use it in GitHub Desktop.
Speculations on an ES5-style KnockoutJS
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
// DESIRED (pending bikeshedding): | |
// Create using special factory function. Will automatically create `ko.observable`s, `ko.observableArray`s, and | |
// `ko.computed`s for you, but hide them behind getters/setters. | |
var viewModel = es5ViewModel({ | |
firstName: "Luke", | |
lastName: "Skywalker", | |
fullName: function () { | |
return this.fullName + this.lastName; | |
}, | |
parents: ["Anakin", "Padme"] | |
}); | |
// If you want commands, attach them manually: functions passed to `es5ViewModel` will become `ko.computed`s. | |
viewModel.drawLightsaber = function () { }; | |
// `applyES5Bindings` is like `ko.applyBindings`, but takes ES5 view models instead of Knockout view models. | |
applyES5Bindings(viewModel, document.getElementById("jedi-info")); | |
// You can set and get properties without the annoying pseudo-getter/setter syntax of observables. | |
viewModel.firstName = "Luuke"; | |
console.log(viewModel.lastName); // Skywalker | |
console.log(viewModel.parents); // Anakin, Padme | |
viewModel.parents = ["Darth Vader", "Queen Amidala"]; | |
console.log(viewModel.fullName); // Luuke Skywalker | |
// Computed observables don't have setters. (I know Knockout has the ability to make this happen, but I think YAGNI). | |
// ----------- | |
// `applyES5Bindings` is the only sticky point: we need to get a Knockout view model from the ES5 one. | |
// SOLUTION 1 | |
// Would look nicer with ES Harmony destructuring assignment: replace first three lines with | |
// `let [viewModel, koBindings] = es5ViewModel({});` | |
var x = es5ViewModel({}); | |
var viewModel = x.viewModel; | |
var koBindings = x.koBindings; | |
ko.applyBindings(koBindings, document.getElementById("jedi-info")); | |
// SOLUTION 1.5 | |
// If we don't need to separate creation from binding, then this could work: | |
var viewModel = boundES5ViewModel(document.getElementById("jedi-info"), {}); | |
// Not sure that's the case very often though. | |
// SOLUTION 2 | |
// Use a map of ES5 VMs to KO VMs. `applyES5Bindings` would do a lookup. | |
// Really only a responsible thing to do with a ES Harmony WeakMap available; otherwise not very memory-conscious. | |
// ES Harmony private names would also do the trick. | |
// SOLUTION 3: | |
var viewModel = es5ViewModel({}); | |
ko.applyBindings(viewModel._koBindings, document.getElementById("jedi-info")); | |
// (could encapsulate access to `_koBindings` inside `applyES5Bindings`.) | |
// SOLUTION 4: | |
// Even more underscores. Expose a _'ed counterpart to all original properties that gives direct access | |
// to the Knockout observable. `applyES5Bindings` would then reconstruct a Knockout view model from those. | |
// CONCLUSION | |
// I think I like solution 3 the most. Normally I would loathe the lack of encapsulation, but view models shouldn't be | |
// used by anyone except rendering code, so nobody else should have to deal with this wart. | |
//---------- | |
// COMPLICATED PARTS: | |
// * Nested ES5 view models/ES5 view models contained in arrays. *Shudder*. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment