Search code examples
jsondata-bindingknockout.jsknockout-mapping-plugin

Knockout Mapping Plugin and Data-Bind from Simple JSON


I'm having some problems figuring out why this simple Knockout mapping isn't working. I'm not sure if the returned JSON is invalid or if my mappings are wrong or if it's simply the bindings.

The data structure is a parent Conversation object with an array of Message objects.

On the bindings I'm using foreach: Conversation at the moment because I have this working if I wrap the whole thing a single element array.

My bindings

<div data-bind="foreach: conversation">
  <div data-bind="foreach: messages">
    <div class="well"> 
      <div data-bind="text: sender_name"></div> 
      <div data-bind="text: subject"></div>
      <div data-bind="text: body"></div>
      <div data-bind="text: updated_at"></div> 
    </div>    
  </div>
</div>  

My ViewModel, faked JSON and mappings

// Sample JSON to return for initialization; 2 second delay

var conversationData = {
  json: $.toJSON(
        {"id":8,"subject":"Hello JB! Email two!",
         "updated_at":"Sep 27",
         "originator":"James Pablo",
         "count_messages":"(2)",
         "messages":[{"subject":"RE: Hello JB! Email two!",
                      "body":"Thanks for the message!",
                      "sender_name":"Joe Flynn","updated_at":"Sep 27"},
                     {"subject":"Hello JB! Email two!",
                      "body":"Body text",
                      "sender_name":"James Pablo",
                      "updated_at":"Sep 27"}
                    ]
        }
  ),
  delay: 1
}



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

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

var map = {
  create: function(options) {
    return new Conversation(options.data);
  },
  messages: function(options) { 
    return new Message(options.data);
  }
}


var ViewModel = function() {
  var self = this;
  self.conversation = ko.observable();

  // Use JSFiddle echo to simulate an AJAX service
  (function() {
    $.ajax({ url:"/echo/json/", data:conversationData, type:"POST",
             success:function(data)
             {
               // Map the returned JSON to the View Model  
               ko.mapping.fromJS(data, map, self.conversation);
             }
           });
   })();  

   console.log(self.conversation());

};

ko.applyBindings(new ViewModel());

This JSFiddle works when I'm returning the JSON data wrapped in a single element array.

If I remove the array wrapper from the JSON in this JSFiddle (which is what I want as I only want to render a single conversation) then I can't get it to work. Any ideas?


Solution

  • Create function only works on arrays.

    Try this

    http://jsfiddle.net/C46pU/2/

    Removed Convension from map literal and did

    self.conversation(new Conversation(data));