knockoutjs - ko.mapping.fromJS not working
Asked Answered
T

2

10

I have just started trying knockout.js. The ko.mapping offers a nifty way to get and map data from server. However I am unable to get the mapping to work.

I have a simple model:

//var helloWorldModel;
var helloWorldModel = {
    name: ko.observable('Default Name'),
    message: ko.observable('Hello World Default')
};


$(document).ready(function() {
  ko.applyBindings(helloWorldModel);
      //a button on the form when clicked calls a server class 
      //to get json output
  $('#CallServerButton').click(getDataFromServer);
});

function getDataFromServer() {
  $.getJSON("HelloSpring/SayJsonHello/chicken.json", function(data) { 
    mapServerData(data);
  });
}

function mapServerData(serverData) {
  helloWorldModel = ko.mapping.fromJS(serverData, helloWorldModel);
  alert(JSON.stringify(serverData));
}

The helloWorldModel has only 2 attributes - exactly the same thing I return from the server. The alert in mapServerData shows -

{"name":"chicken","message":"JSON hello world"}

I have looked up other posts regarding similar problem, but none of them seemed to be solve this issue. Maybe I am missing something very basic - wondering if anyone can point it out.

Also note if I do not declare the model upfront and use

 helloWorldModel = ko.mapping.fromJS(serverData);

it is mapping the data to my form correctly.

Trim answered 21/2, 2014 at 3:6 Comment(1)
You can also make this work with writing: function mapServerData(serverData) { ko.mapping.fromJS(serverData, {}, /* empty object for the mapping options */, helloWorldModel); alert(JSON.stringify(serverData)); } see here why this will also work:#13323304Boyce
T
21

From Richard's reply and then a little more investigation into this I think that the way I was initializing the model is incorrect. I guess that one cannot use an existing view model and then expect it to work with mapper plugin. So instead you initialize view model with raw JSON data using the ko.mapping.fromJS:

var helloWorldModel;

$(document).ready(function() {
  var defaultData = {
      name: 'Default Name',
      message: 'Hello World Default'
  };

  helloWorldModel = ko.mapping.fromJS(defaultData);
  ko.applyBindings(helloWorldModel);
  $('#CallServerButton').click(getDataFromServer);
});

function getDataFromServer() {
  $.getJSON("HelloSpring/SayJsonHello/chicken.json", function(data) { 
    mapServerData(data);
  });
}

function mapServerData(serverData) {
  alert(JSON.stringify(serverData));
  ko.mapping.fromJS(serverData, helloWorldModel);
}

This code works and provides the expected behavior

Trim answered 21/2, 2014 at 5:35 Comment(2)
great answer and still helping 2.5 years later. This was my exact situation.Calysta
Yep, mapping.toJS relies on mapping.fromJS to store the list of items copied from the source JSON object. This is subtly mentioned in the documentation, which shows that toJS "remembers" which observables were mapped vs manually added.Newsreel
M
14

You can't just overwrite your model by reassigning it this way.

When you do:

ko.applyBindings(helloWorldModel);

You are saying "bind the model helloWorldModel to the page". Knockout then goes through and hooks up the observables in that model and binds them with the page.

Now when you overwrite your form model here:

helloWorldModel = ko.mapping.fromJS(serverData, helloWorldModel);

It is overwriting your model object with a brand new object with entirely new observables in it.

To fix it you need to change this line to just:

ko.mapping.fromJS(serverData, helloWorldModel);

This takes care of the properties inside the model and reassigns them for you, without overwriting your model.

Mattah answered 21/2, 2014 at 4:18 Comment(1)
Makes sense. I changed my code to remove the assignment, however the issue persists.Trim

© 2022 - 2024 — McMap. All rights reserved.