There are various problems with your code, but it won't throw an error because the mapping plugin is used improperly.
The problem of scope
First, fullAddress
is a property of Address
instances, so you should prefix it with address.
Second, the with
binding tells Knockout to look for editingPerson.savePerson
which doesn't exist. So you have to change the binding to the root scope, like so: click: $root.savePerson
.
<!-- current --> inputAddress: <input data-bind="value: fullAddress">
<!-- correct --> inputAddress: <input data-bind="value: address.fullAddress">
<!--current --> <button data-bind="click:savePerson" type="button">Save</button>
<!--correct --> <button data-bind="click:$root.savePerson" type="button">Save</button>
It is also advised to use objects as constructor parameter, allowing for easier use in combination with the mapping plugin
and should you wish to leave out one property.
The mapping plugin
The mapping plugin documentation clearly states that:
All properties of an object are converted into an observable.
This means that you cannot include computed observables and expect them to just work. Indeed, the documentation has a part about augmenting JS objects with computed observables here. I might be wrong, but from my tests and the docs, it doesn't seem so that the create
functions for mapping can be used for nested objects. Following this documentation, you don't need to create all observable properties explicitly, as a single call to ko.mapping.fromJS
can instantiate them. Your new Person
constructor would look like this:
function Person(options){
// because these arrays contain nested objects with computed observables,
// they should have a special create function
var self = this, mapping = {
'amounts': { create: function(options) { return new Amount(options.data); }},
'address': { create: function(options) { return new Address(options.data); }}
};
// instantiates all properties, eg. surname, name, id
ko.mapping.fromJS(options, mapping, this);
self.fullName = ko.computed(function() {
return self.name()+" - "+self.surname();
});
}
Another minor 'nit-pick': you can only use the mapping plugin's create
functions on named object properties, so in your original fiddle, the plugin will never find the persons
array because it is the data root.
Check out this fiddle for the complete solution.