Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize a Knockout viewmodel when initial viewmodel load is empty

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 );
like image 896
Bert G Avatar asked Oct 19 '12 20:10

Bert G


2 Answers

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);
like image 52
Jeff Mercado Avatar answered Oct 03 '22 18:10

Jeff Mercado


var data = {
    CourseList: DataFromServer.CourseList || ko.observableArray([]) ,
    ScheduleList: DataFromServer.ScheduleList  || ko.observableArray([])
    };
like image 35
Ray Avatar answered Oct 03 '22 19:10

Ray