Ok let's go through a simple example imagining we want to show some activities on a page.
- Let's say your data returned is an enumeration of activities which all have certain properties, then your activity might look like something like this:
var ActivityType = function (data) {
var self = this;
self.Id = ko.observable(data.Id);
self.Name = ko.observable(data.Name);
self.Description = ko.observable(data.Description);
self.Selected = ko.observable(data.Selected); };
Then you have a viewmodel which has a property called Activities which needs to mapped to this activity Model, so when you get your activities enumeration it automatically produces the same of number New ActivityTypes for you in that array.
var activitiesViewModel = {};
so we define a mapping utility for that (simply saying new ActivityTypes are the ones with a different Id so then create a new one):
var ActivityTypeDataMappingOptions = {
key: function (data) {
return data.Id;
}, create: function (options) {
return new ActivityType(options.data, null);
}
}
So now we need the activities property on the view model:
activitiesViewModel.Activities = mapping.fromJS([])
This means make an observable array based on the mapping data.
Let's say you have a datacontext defined that gives you your data then in the callback of that:
datacontext.getActivities(function (data) {
mapping.fromJS(data.Activities, ActivityTypeDataMappingOptions, activitiesViewModel.Activities);
ko.applyBindings(activitiesViewModel);
});
mapping.fromJS takes 3 params, first one the collection thats going to have the data, second one the mapping utility we defined so make new activities out of and last the property on the view model that holds the observable collection.
So now you can use this like:
<ul data-bind="foreach: Activities">
<li><input type='text' data-bind="value: Name" /></li>
</ul>
<button data-bind="click: updateActivities">Update Activities</button>
- note: In this example view model is a singleton but you might want to depending on your usage make it a instantiatable object using the revealing prototype pattern. Then when you are calling ko.applyBindings you need to pass new activitiesViewModel() as the param.
Now for updating and sending back the results we need to define updateActivities:
activitiesViewModel.updateActivities = function(){
datacontext.setActivities({
activities : ko.toJSON(activitiesViewModel.Activities)
}, function(data){
if (data) alert("all done");
});
};
You can also bind this function to change even of the input but that would be far too many API calls, so I don't recommend it.
If you are making lots of these models which is then used by a view model you will quickly realize you are doing a lot of modelling that is already done on the server side. If you write some server side code that automatically generates js files containing the model e.g. ActivityType in my example, you can simply use requireJS to import them in the view model file and then use them across the application. This will allow property name changes and updates to be automatically available on the front end by only updating the model in the backend.