Knockout.js is a MV* (MVVM) framework with powerful two-way data-binding and pub-sub mechanisms. However to use it, code feels akward:
var model = {
firstName: ko.observable('John'),
lastName: ko.observable('Doe'),
age: ko.observable(30)
};
model.firstName('Jane');
model.age(model.age() + 1);
wouldn't it be nice to just use
model.firstName = 'Jane';
model.age++;
knockout-es5-option4 solves this with ECMAScript 5 Properties, so you can do just that!
var model = ko.observe({
firstName: 'Bob',
lastName: 'Doe',
cars: [{
make: 'Ford',
model: 'F150'
}, {
make: 'BMW',
model: '328i'
}]
})
ko.defineComputedProperty(model, 'ownershipSummary', function() {
return this.firstName + ' ' + this.lastName + ' owns: ' + this.cars.map(function(c) {
return c.make + ' ' + c.model
}).join(', ');
})
model.ownershipSummary
// => Bob Doe owns: Ford F150, BMW 328i
model.firstName = 'Jon';
model.ownershipSummary
// => Jon Doe owns: Ford F150, BMW 328i
model.cars[0].model = 'Mustang';
model.ownershipSummary
// => Jon Doe owns: Ford Mustang, BMW 328i
If you need to access the underlying observable, they are available as non-enumerable properties with a proceeding underscore.
var model = ko.observe({
name: 'Bob'
})
model._name.subscribe(function(newName) {
console.log('Hi ' + newName)
})
object
: The object to add properties wrapping knockout observables. This is also the return valuedefaults
(optional): A set of default values for those properties. This allows you to essentially clone an object without modifying it with the observable properties. Defaults to theobject
parameter.options
(optional): See options.
A thin wrapper around observe
that returns a new object. Literally it is:
ko.observableObject = function(defaults, options) {
return ko.observe({}, defaults, options)
}
object
: the object to add the property to.propertyName
: the name of the property. It will delete any existing properties that don't have property descriptors.default
: the value the observable should be initialized to.options
: See options.
object
: the object to add the property to.propertyName
: the name of the property. It will delete any existing properties that don't have property descriptors.definition
: the definition of the computed that will be passed toko.computed
.options
: See [options][#options].
deep
: Deeply observe the object or array. Defaults to true.arrayMapping
: Specify a way to map items in an array that are the same, so that an array doesn't have to be in order for items to match up. For example:
var person = ko.observe({
id: 1,
name: 'Jane',
cars: [{
id: 1,
make: 'BMW',
model: '3-series'
}, {
id: 2,
make: 'Toyota',
model: 'Tundra'
}]
})
// Update our model to have a year on the cars. Match cars based on the 'id' property.
ko.observe(person, {
cars: [{
id: 2,
year: 2015
}, {
id: 3,
make: 'Tesla'
model: 'Model S',
year: 2014
}]
}, {
arrayMapping: {
cars: 'id'
}
})
person.should.deep.equal({
id: 1,
name: 'Jane',
cars: [{
id: 1,
make: 'BMW',
model: '3-series'
}, {
id: 2,
make: 'Toyota',
model: 'Tundra',
year: 2015
}, {
id: 3,
make: 'Tesla'
model: 'Model S',
year: 2014
}]
})
remove
: remove an item from the arrayremoveAll
remove all items from the array. Equivalent to assigning a new array.replace
: replace an item in the array with another one.toggle
: Add an item to the array if it is not there, otherwise remove it.
- Does not depend on WeakMap for easier compatibility. However, simply deleting an property does not release it from memory. You must also delete the underscore prefixed property too. I found in my usage I never ended up deleting indivdual properties, but just whole objects, so this has not been an issue.
- No referrence needed to knockout to access the observable. When using AMDs and in view code, having the observable directly on the object has been a nice convenience.
- Deeply observes objects. Currently knockout-es5 9does not support deep tracking]().
In 2012, trying to find a solution to wrap knockout observables in ES5 properties, I found this gist by Domenic Denicola of his brainstormings about potential options, before Steve Sanderson created knockout-es5. So I decided to go with his Solution #4, to expose the observables on the object with a proceeding underscore in front of them. However I did this while working at Microsoft, and it did not get released as open source until Janurary 2015.