Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout.js mapping JSON object to Javascript Object

I have a problem mapping a Json object recieved from the server into a predefined Javascript-object which contains all the necessary functions which are used in the bindings

Javascript code is the following

function Person(FirstName, LastName, Friends) {
    var self = this;
    self.FirstName = ko.observable(FirstName);
    self.LastName = ko.observable(LastName);
    self.FullName = ko.computed(function () {
        return self.FirstName() + ' ' + self.LastName();
    })
    self.Friends = ko.observableArray(Friends);
    self.AddFriend = function () {
        self.Friends.push(new Person('new', 'friend'));
    };
    self.DeleteFriend = function (friend) {
        self.Friends.remove(friend);
    };      
}

var viewModel = new Person();

$(document).ready(function () {
    $.ajax({
        url: 'Home/GetPerson',
        dataType: 'json',
        type: 'GET',
        success: function (jsonResult) {
            viewModel = ko.mapping.fromJS(jsonResult);
            ko.applyBindings(viewModel);
        }
    });
});

HTML:

<p>First name: <input data-bind="value: FirstName" /></p>
<p>Last name: <input data-bind="value: LastName" /></p>
<p>Full name: <span data-bind="text: FullName" /></p>
<p>#Friends: <span data-bind="text: Friends().length" /></p>
@*Allow maximum of 5 friends*@
<p><button data-bind="click: AddFriend, text:'add new friend', enable:Friends().length < 5" /></p>
<br>
@*define how friends should be rendered*@
<table data-bind="foreach: Friends">
    <tr>
        <td>First name: <input data-bind="value: FirstName" /></td>
        <td>Last name: <input data-bind="value: LastName" /></td>
        <td>Full name: <span data-bind="text: FullName" /></td> 
        <td><button data-bind="click: function(){ $parent.DeleteFriend($data) }, text:'delete'"/></td> 
    </tr>
</table>

My ServerSide MVC code for getting initial data looks like:

    public ActionResult GetPerson()
    {
         Person person = new Person{FirstName = "My", LastName="Name",
                        Friends = new List<Person>
                        {
                             new Person{FirstName = "Friend", LastName="Number1"},
                             new Person{FirstName = "Friend", LastName="Number2"}
                        }
        };
        return Json(person, JsonRequestBehavior.AllowGet);
    }

I am trying to use the mapping plugin to load the Json into my Javascript object so everything is available for the bindings (The add-function and the computed properties on the Friend objects).

When I use the mapping plugin it does not seem to work. When using the plugin the AddFriend method is not available during the binding. Is it possible to populate the JavaScript Person object by using the mapping plugin or must everything be done manually?

like image 479
DiederikTiemstra Avatar asked Jan 10 '12 15:01

DiederikTiemstra


1 Answers

You can look at passing mapping options to the mapping plugin, specifically a create callback as described here.

Something like:

var mapping = {
    create: function(options) {
        var person = options.data,
            friends = ko.utils.arrayMap(person.Friends, function(friend) {
               return new Person(friend.FirstName, friend.LastName);   
            });

        return new Person(person.FirstName, person.LastName, friends);
    }
};

Sample: http://jsfiddle.net/rniemeyer/5EWDG/

However, in this case, you don't get a lot of power from the mapping plugin and you could just do it without by calling the Person constructor yourself and mapping the Friends array to Person objects in the constructor like: http://jsfiddle.net/rniemeyer/mewZD/

One other note from your HTML: Make sure that for elements that contain content, that you specify the starting and ending tags (span and button were not this way in your code). KO will have problems if you do not specify them properly.

like image 125
RP Niemeyer Avatar answered Nov 24 '22 17:11

RP Niemeyer