3

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.

Community
  • 1
  • 1
Greg Smith
  • 2,449
  • 2
  • 24
  • 37
  • 2
    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 Nov 13 '12 at 07:46
  • 1
    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 Nov 13 '12 at 07:50

1 Answers1

3

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.

Greg Smith
  • 2,449
  • 2
  • 24
  • 37
  • 1
    Another suggestion would be make `MassiveDataModel` a property on the model you send to the view, instead of using the Viewbag. It doesn't make a big difference, but its a good habit to be in. – Kyeotic Nov 13 '12 at 16:19
  • our naming convention of 'DataModelViewContext' may make more sense than 'Massive'. Avoiding the ViewBag is a must...interesting concept, but there's really no reason to have properties @ run-time that don't already exist – beauXjames Oct 24 '13 at 20:34
  • One thing I have noticed in using this type of pattern is that, assuming MassiveDataModel has other sub-objects (which would by default be null when constructing a new MassiveDataModel()).... you have to make sure to provide a default constructor that ensures all the sub-objects have been "new"-ed up as well. Otherwise, when you later try to populate those sub-objects and access them via bindings in your HTML..... it throws weird errors. – Jason Parker Mar 03 '14 at 20:02