I am using Knockout to implement a course list selection tool. I am using the approach below to populate the data (MVC3/Razor), so that when the viewmodel is initially populated, I have no issues working with each KO array (i.e. CourseList, ScheduleList). However, when the initial load from the server returns zero rows, meaning that the viewmodel 'ScheduleList' property is empty, then it's not possible to call any methods such as .push() or .removeAll(). Presumably this means that the observable array was never created since there was nothing to fill it with. When the model is filled, the ScheduleList property is populated with a List. What is the best way to instantiate it when the MVC action returns it as empty? There is a jsFiddle that seems to address it, but when I try to use the 'create' option, it renders my entire model blank. I am not sure what the syntax is of the 'create' option. The jsFiddle is here: http://jsfiddle.net/rniemeyer/WQGVC/
// Get the data from the server
var DataFromServer = @Html.Raw(Json.Encode(Model));
// Data property in viewmodel
var data = {
"CourseList": DataFromServer.CourseList ,
"ScheduleList": DataFromServer.ScheduleList
};
$(function() {
// Populate Data property
viewModel.Data = ko.mapping.fromJS(data);
// ko.applyBindings(viewModel, mappingOptions);
ko.applyBindings(viewModel);
});
When the initial page load does not populate ScheduleList, then the following code throws an error. If the initial page load contained data, then you could call .removeAll() and .push() etc.
var oneA= 'abc';
// push not working
this.Data.ScheduleList.push( oneA );
Set up your mapping parameters to make it so on creation, you give it a certain structure. Then it will do the updates for you.
What is most likely happening is that your DataFromServer
doesn't actually contain a ScheduleList
property at all. So when it is mapped, a corresponding property is never made. The mapper will only map existing properties to observables.
You need to set in your create
options for the view model to add empty arrays when either array is not set. That way, your view model will end up with corresponding observable arrays in place.
By ensuring that CourseList
or ScheduleList
is an array, the mapped view model will map them as observableArray
objects so your code will work as you expected.
var DataFromServer = {
'CourseList': [1,2,3]
//, 'ScheduleList': []
};
var dataMappingOptions = {
'create': function (options) {
var data = options.data;
data.CourseList = data.CourseList || [];
data.ScheduleList = data.ScheduleList || [];
return ko.mapping.fromJS(data);
}
};
viewModel.Data = ko.mapping.fromJS(DataFromServer, dataMappingOptions);