3
votes

Using knockoutjs, i'm attempting to map a large and complex piece of data. I'm using the revealing module pattern.

In order to make all elements of the object observable, i'm using the mapping plugin. However, i've hit an issue: I cannot find, anywhere, an example of using ko.mapping.fromJS() where some initial data is not mapped on the viewmodel object, but is mapped later, after - in my case - an ajax call has been made and some data retrieved. That is, I do not have any initial data, so need the initial mapping to be full of nulls, empties, or defaults.

This is the only info anywhere that is sort of related

Knockout JS mapping plugin without initial data / empty form

but this doesn't really solve the same problem - or at least, I can't make it solve the same problem.

And here's roughly the code i've got.

var viewModel = function(){
    var farmyard = *** What?? ***;

    var refreshData = function(){
        var temp = null;
        $.ajax(
            // awesome server call etc
            success: function(data){
                temp = data;
            }
        );
        ko.mapping.fromJS(temp, farmyard);
    };

    return{
            farmyard: farmyard,
            refreshData: refreshData
        }
};

$(function(){
   var vm = new viewModel();
   ko.applybindings(vm);

   $('#something).on('click',function(){
       vm.refreshData();
   });
});

So, my question is, what is the farmyard on the initial load of this object? At the moment I have had to setup empty objects to make this work, handcoding every element of every object, and as mentioned, the object hierarchy being mapped is large and complex, so this is not ideal. Any help much appreciated.

Thanks.

1
I'm curious why you can't send an actual empty viewmodel with the first page request? Or, if the data really is seperate, perform binding at the same time you first get the initial viewmodel, instead of on DOM ready. - Kyeotic
Thanks for the comment. I was initially performing the data binding when the object became available (ie, after the ajax request), but this caused problems as it was calling ko.applyBindings() every time the ajax call was made (ie, on a click event). However, the first part of your comment is really what I should be doing, and so obvious...a real wood for the trees moment I think. Thanks. - Greg Smith

1 Answers

3
votes

I've resolved this by sending an empty data model into the view (this is .NET MVC) as part of the ViewBag property, and using a library called Ngon (https://github.com/brooklynDev/NGon).

public ViewREsult Index()
{
    var massiveDataModel = new MassiveDataModel();

    ViewBag.NGon.Stuff = massiveDataModel;

    return View();
}

And in the script:

var viewModel = function(){
var farmyard = ko.mapping.fromJS(ngon.Stuff);

var refreshData = function(){
    var temp = null;
    $.ajax(
        // awesome server call etc
        success: function(data){
            temp = data;
        }
    );
    ko.mapping.fromJS(temp, farmyard);
};

return{
        farmyard: farmyard,
        refreshData: refreshData
    }
};

    $(function(){
       var vm = new viewModel();
       ko.applybindings(vm);

       $('#something).on('click',function(){
           vm.refreshData();
       });
    });

Was so caught up with trying to solve the problem in a certain way, couldn't see the obvious solution. Thanks to Tyrsius for the different perspective.