0

Let's say I have a list of knockout bindings placed in a nested/namespaced object, resembling this:

var bindings = {
    event: {
        eventid: ko.observable(),
        office: ko.observable(),

        employee: {
            name: ko.observable(),
            group: ko.observable()
        }
    },
    ...
}

Now let's say there are a number of different sets of data that might be loaded into this - so one does an ajax query and gets a JSON result like this:

{
    "defaults": {
        "event": {
            "eventid": 1234,

            "employee": {
                "name": "John Smith"
            }
        },
        ...
    }
}

Note that not every binding has a default value - but all defaults are mapped to a binding. What I want to do is read the defaults into whatever knockout binding they correspond to.

There are definitely ways to traverse a nested object and read its values. Adding an extra argument to that example, I can keep track of the default's full key (eg event.employee.name). Where I'm getting stumped is taking the default's key and using it to target the associated knockout binding. Obviously, even if i have key = "event.employee.name", bindings.key doesn't reference what I want. I can only think of using eval(), and that leaves me with a bad taste in my mouth.

How would one go about using a key to reference the same location in a different object? Perhaps knockout provides a way to auto-map an object to its bindings, and I've just overlooked it? Any insight would be helpful. Thanks in advance!

Community
  • 1
  • 1
CodeMoose
  • 2,964
  • 4
  • 31
  • 56

2 Answers2

2

I would suggest you have a look at the Knockout Mapping Plugin which will do most of what you want to do. If that doesn't workout then you can turn your bindings object into a series of constructor functions that accepts a data parameter. Something like

var Employee = function (data){
 var self = this;
   self.name = ko.observbale(data.name || '');
   self.group = ko.observable(data.group);
};

var Event = function(data){
 var self = this;
   self.eventid = ko.observable(data.id || 0);
   self.office = ko.observable(data.office || '');
   self.employee = ko.observable(new Employee(data.employee));
};


var bindings = function(data){
    var self = this;
   self.event = ko.observable(new Event(data));
}
Nathan Fisher
  • 7,961
  • 3
  • 47
  • 68
  • Huh, well look at that. That's clever, I never thought to stick a function inside an observable. Wish I could +2 this! – CodeMoose Sep 19 '14 at 14:41
0

I'll be putting Nathan Fisher's solution into a future update, but I wanted to share the fix I found for now as well. Each time the defaults object recurses, I simply pass the corresponding bindings object instead of tracking the entire keypath.

var setToDefaults = function(data){
    loopDefaults(data.defaults, bindings);
};

var loopDefaults = function(defaults, targ){
    for(var d in defaults){
        if(defaults.hasOwnProperty(d) && defaults[d]!==null){
            if(typeof(defaults[d])=="object"){
                loopDefaults(defaults[d], targ[d]);
            }else{
                // defaults[d] is a value - set to corresponding knockout binding
                targ[d](defaults[d]);
            }
        }
    }
}; 
CodeMoose
  • 2,964
  • 4
  • 31
  • 56