Search code examples
javascriptdynamicknockout.jsko.observablearray

Knockout.js dynamic binding of observables


I am trying to utilize knockout to create an editable table. I have a JSON object that has a collection of both headings and table data. This table needs to be built using any object. It will loop over the JSON object to create ko.observableArray and the ko.observables to populate it. I have been able to do that. My problem is that the ko.observables are not being data bound.

Here is a snippet of my JavaScript:

EditableTableVM.prototype.load = function() {
    this.headings = this.buildKO_ObservableArray(new Heading(), this.dataRepo.HEADINGS);
    this.listings = this.buildKO_ObservableArray(new Listing(), this.dataRepo.LISTINGS);
}

/*
 * Dynamically creates a ko.observableArray from a JS array
 * Params: JSClass - new instance of a class
 * Params: baseArray - array of objects to create the observable array
 * Returns: Observable arary of JS object with ko.observables
 */
EditableTableVM.prototype.buildKO_ObservableArray = function(JSClass, baseArray) {
    var newArray = ko.observableArray([]);

    for(var i = 0, j = baseArray.length; i < j; i++) {
        var baseObj = baseArray[i];

        //new class is the class with ko.observables properties
        var newClass = this.buildKO_Observable(JSClass, baseObj);
        newArray.push(newClass);
    }

    return newArray;
}

/*
 * Dynamically create ko.observable from properties in an object
 * Params: JSClass - new instance of a class
 * Params: jsObject - object to created observables with
 * Returns: JS object with ko.observables
 */
EditableTableVM.prototype.buildKO_Observable = function(JSClass, jsObj) {
    for (var key in jsObj) {
        if (jsObj.hasOwnProperty(key)) {
            JSClass[key] = ko.observable(jsObj[key]);
        }
    }

    return JSClass;
}

Here is my Fiddle http://jsfiddle.net/breck421/YFNLX/ with it working up to the point I described earlier.

I am not sure if what I am trying to do is possible or not and would really appreciate another set of eyes on this.

Thanks,

Jordan


Solution

  • The issue you're running into is that when you're mapping your JSON to knockout-enabled view models, you aren't handling children with arrays correctly. Your mapping isn't going deep enough.

    If you check the following:

    EditableTableVM.listings()[0].LISTING()[0];
    

    you'll see that the properties of that object are just values, not ko.observables.

    Rather than try to build this mapping from scratch, I'd recommend using one of the knockout mapping plugins : either the knockout mapping plugin here : https://github.com/SteveSanderson/knockout.mapping with it's documentation here : http://knockoutjs.com/documentation/plugins-mapping.html or the newer Knockout ViewModel plugin here : http://coderenaissance.github.io/knockout.viewmodel/

    I've updated your fiddle with the knockout mapping plugin : http://jsfiddle.net/rrahlf/YFNLX/2/ and now your values bind correctly.

    Good luck!