Mathew A
Mathew A

Reputation: 15

Convert object received from server into object with ko observable properties

I am having issues with what seemed like an easy idea.

I am trying to create ko.observable()'s dynamically from server provided data.

The server is sending me a ~240 value JSON array. I want to create an observable for each one as I am putting them into an online form.

First try

function AppViewModel() {

  var self = this;

  var data = {};

  $.getJSON("/record/20001", function(data) {
    $.each(data, function(i, val) {
      self.data[i] = ko.observable(val);
    });
  });


  self.test = 5;

  self.test2 = ko.observable(69);


}

vm = new AppViewModel();
ko.applyBindings(vm);

With this I was unable to access any of the data.

Second try which worked

function AppViewModel() {

    var self = this;
    self.abnorm_comment = ko.observable();
    self.abnorm_test1 = ko.observable();
    self.abo_sys_spec = ko.observable();
    self.access_location = ko.observable();
    self.ace_inhibit = ko.observable();

    /* 
    A myriad of line like these, written by hand
    */

    self.xray_other = ko.observable();


    $.getJSON("/record/20001", function (data) {
        $.each(data, function (i, val) {
            self[i](val);
        });
    });

    self.test = 5;

    self.test2 = ko.observable(69);


}

What I am trying to do

function AppViewModel() {

    var self = this;

    var data = {};


    $.getJSON("/record/20001", function (data) {
        $.each(data, function (i, val) {
            self.data[i] = ko.observable(val);
        });
    });

}

And access it like so:

<input type="text" data-bind="value: data.case_id">

For the first try my view model has no data in it. If I pull up the vm variable in the Chrome console it does have the data though.

Am I doing something wrong here? The second way that works does not look very nice with so many observables.

Please let me know if I am missing something obvious

Personal Solution

It ended up that I was having a race condition between applying the bindings and the the AJAX server request. I also ended up using the plugin as recommended by @JotaBe

Upvotes: 0

Views: 1404

Answers (2)

JotaBe
JotaBe

Reputation: 39025

You can use the ko.mapping plugin which will do it for you.

The advantages are that this plugin is well tested, and is able to map more complex data, like arrays, or nested properties.

You can map from JSON, or from an already instanced JavaScript object. The synatx is as simple as this:

var viewModel = ko.mapping.fromJSON(data);

Another advantage is that it can also update your local mapped copy from new updated data coming from the server, without rebuilding the whole object. This also helps in updating the view, without the need to rebuild (or unbind) it.

And a final advantage is taht it also allows to get back the JSON or JavaScript object if you need to post it back to the server, simply like this:

var unmapped = ko.mapping.toJS(viewModel);

Upvotes: 1

Geoff
Geoff

Reputation: 9340

This has worked reliably for me in the past:

jsonToObservable = function (obj, data) {

    for (var p in data) {
        var temp = data[p];

        obj[p] = ko.observable(temp);

    }
};

Upvotes: 2

Related Questions