knockout.js - KnockoutJS - Convention based auto-mapping using mapping plugin not working as expected -
i trying grips knockoutjs. have had bit of success replicating steven sanderson's seminar example mix11 (person friends on twitter) .
i trying extend can json asp.net mvc4 controller, , automatically bind data viewmodel.
i managed working quite manual mapping of json object knockout objects observables, however, simple model low complexity. when come use real, models more complicated, , manual mapping less attractive.
i think being asp.net mvc4 page irrelevant, getting valid json markup.
here full mark up:
<!doctype html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>person</title> <link href="/knockoutsample/content/site.css" rel="stylesheet"/> <script src="/knockoutsample/scripts/jquery-2.0.0.js"></script> <script src="/knockoutsample/scripts/modernizr-2.6.2.js"></script> <script src="/knockoutsample/scripts/knockout-2.2.1.debug.js"></script> <script src="/knockoutsample/scripts/knockout.mapping-latest.js"></script> </head> <body> <h2>person</h2> <p>full name: <span data-bind="text: fullname" ></span></p> <p>first name: <input type="text" data-bind="value: firstname" /></p> <p>last name: <input type="text" data-bind="value: lastname" /></p> <h2>friends (<span data-bind="text: friends().length"></span>)</h2> <ol data-bind="template: { name: 'friendstemplate', foreach:friends}"></ol> <script id="friendstemplate" type="text/html"> <li> <input data-bind="value: fullname"/> <button data-bind="click: removefriend">remove</button> <label><input type="checkbox" data-bind="checked: isontwitter" />is on twitter</label> <input type="text" placeholder="please enter username" data-bind="value: twittername, visible: isontwitter" /> </li> </script> <button data-bind="click: addfriend, enable: friends().length < 5">add friend</button> <button data-bind="click: save">save</button> <script type="text/javascript"> function friend() { function instanceofconstructor(newfriend) { return { fullname: newfriend.fullname, isontwitter: newfriend.isontwitter, twittername: newfriend.twittername, removefriend: function () { viewmodel.friends.remove(this); } }; } function paramatisedconstructor(name, ontwitter, twittername) { return { fullname: ko.observable(name), isontwitter: ko.observable(ontwitter), twittername: ko.observable(twittername), removefriend: function () { viewmodel.friends.remove(this); } }; } switch (arguments.length) { case 1 : return instanceofconstructor(arguments[0]); case 3 : return paramatisedconstructor(arguments[0], arguments[1], arguments[2]); } } var viewmodel = { firstname : ko.observable(), lastname: ko.observable(), friends: ko.observablearray(), addfriend: function () { this.friends.push(new friend("new friend", false, null)); }, save: function () { $.ajax({ url: "/knockoutsample/main/person", type: "post", data: ko.tojson(this), contenttype: "application/json", }).success(function(result){ alert(result.message); }).fail(function (data) { alert(data); }); } }; viewmodel.fullname = ko.dependentobservable(function () { return this.firstname() + " " + this.lastname(); }, viewmodel); ko.applybindings(viewmodel); var initialdata = '{"firstname":"ian","lastname":"robertson","friends":[{"isontwitter":false,"twittername":"","fullname":"friend one"},{"isontwitter":true,"twittername":"@friendtwo","fullname":"friend two"}]}'; var tmp = ko.mapping.fromjson(initialdata); //convention based auto-mapping not work //ko.mapping.fromjson(initialdata, viewmodel); //manual mapping work viewmodel.firstname(tmp.firstname()); viewmodel.lastname(tmp.lastname()); $.each(tmp.friends(), function (i, _friend) { viewmodel.friends.push(new friend(_friend)); }); </script> </body> </html>
i hoping possible avoid manual mapping @ end:
//convention based auto-mapping not work //ko.mapping.fromjson(initialdata, viewmodel); //manual mapping work viewmodel.firstname(tmp.firstname()); viewmodel.lastname(tmp.lastname()); $.each(tmp.friends(), function (i, _friend) { viewmodel.friends.push(new friend(_friend)); });
any pointers on how can use mapping plugin avoid manual mapping appreciated.
update:
<script type="text/javascript"> function friend(name, ontwitter, twittername) { return { fullname: ko.observable(name), isontwitter: ko.observable(ontwitter), twittername: ko.observable(twittername), removefriend: function () { viewmodel.friends.remove(this); } }; } var initialdata = '@html.raw(viewbag.initialdata)'; var viewmodel = { firstname: ko.observable(), lastname: ko.observable(), friends: ko.observablearray() }; viewmodel = ko.mapping.fromjson(initialdata, viewmodel); viewmodel.save = function () { $.ajax({ url: "@url.action("person")", type: "post", data: ko.tojson(this), contenttype: "application/json", }).success(function (result) { alert(result.message); }).fail(function (data) { alert(data); }); }; viewmodel.addfriend = function () { this.friends.push(new friend("new friend", false, null)); }; try { viewmodel.fullname = ko.dependentobservable(function () { return this.firstname() + " " + this.lastname(); }, viewmodel); $.each(viewmodel.friends(), function (i, _friend) { _friend.removefriend = function () { viewmodel.friends.remove(this); } }); ko.applybindings(viewmodel); } catch (e) { alert(e); }
this solution wanted achieve. thing continue try , improve upon using jquery $.each function add "removefriend" function each friend element in array.
you can use fromjs , tojs functions map viewmodel raw data , viewmodel.
var tmp = ko.mapping.fromjs(ko.mapping.tojs(viewmodel));
Comments
Post a Comment