Knockout.js Make every nested object an Observable

frapontillo picture frapontillo · May 11, 2012 · Viewed 40.1k times · Source

I am using Knockout.js as a MVVM library to bind my data to some pages. I'm currently building a library to make REST calls to a web service. My RESTful web service returns a simple structure:

{
    id : 1,
    details: {
        name: "Johnny",
        surname: "Boy"
    }
}

I have an observable main parent, myObject. When I do

myObject(ko.mapping.fromJS(data))

the observables in myObject are:

  • id
  • name
  • surname

How can I make details (and theoretically any object in the structure an observable)? I need this behavior so that i can set a computed observable on details and get noticed as soon as any of the internal data changes.

I have set up a basic recursive function which should do the trick. It doesn't, of course, myObject.details doesn't become an observable.

// Makes every object in the tree an observable.
var makeAllObservables = function () {
    makeChildrenObservables(myObject);
};
var makeChildrenObservables = function (object) {
    // Make the parent an observable if it's not already
    if (!ko.isObservable(object)) {
        if ($.isArray(object))
            object = ko.observableArray(object);
        else
            object = ko.observable(object);
    }
    // Loop through its children
    for (var child in object()) {
        makeChildrenObservables(object()[child]);
    }
};

I'm pretty sure it's something about incorrect references, but how can I solve this? Thank you.

Answer

Paolo del Mundo picture Paolo del Mundo · May 11, 2012

I would use the knockout mapping plugin.

var jsonData = {
    id : 1,
    details: {
        name: "Johnny",
        surname: "Boy"
    }
}

var yourMapping = {
    'details': {
        create: function(options) {
            return Details(options.data);
        }
    }
}

function Details(data) {
    ko.mapping.fromJS(data, {}, this);
}

function YourObjectName() {
    ko.mapping.fromJS(jsonData, yourMapping, this);
}

This will create your object hierarchy with all of the children as observables.