Expected outcome
- Having a C# Dog class with name and age-properties.
- When the page loads, it automatically loads the dog using jQuery ajax (serialized as json) and creates a knockout viewmodel.
- ViewModel should automatically add properties from the C# model.
- The knockout ViewModel should be able to have extra computed methods for validating form for example.
- The ViewModel should be able to save the dog using ajax.
Installing components
Install Knockout.Mapping using NuGet, this will automatically install Knockout.
Create Model
First, create the dog, a simple C# plain object with two properties: Name and Age
public class Dog { public string Name { get; set; } public int Age { get; set; } }
Create MVC Controller
Then create a empty DogController and add a empty Index method. The Load method just creates a simple instance of a dog and returns it as Json, and finally the Save method only accepts post data and just returns a formatted string in Json-format containing the updated Dog
public class DogController : Controller { public virtual ActionResult Index() { return View(); } public ActionResult Load() { return Json(new Dog { Name = "Rambo", Age = 5 }, JsonRequestBehavior.AllowGet); } [HttpPost] public ActionResult Save(Dog dog) { return Json(new { Status = string.Format("Success, saved {0} with age: {1}", dog.Name, dog.Age) }); } }
Create View
Create empty Index View and add script-references
<script src="@Url.Content("~/Scripts/knockout.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/knockout-mapping-latest.js")" type="text/javascript"></script>
Then you add a form containing the knockout bindings bound to the observables on the ViewModel. Two input boxes data bound to Name and Age, the submit-action to “save”, a function on the JavsScript ViewModel, and finally data-bind the submit button so it’s enabled only if the model is valid.
<form method="POST" data-bind="submit: save"> <div>Name:</div> <div><input type="text" data-bind="value: Name" /></div> <div>Age:</div> <div><input type="text" data-bind="value: Age" /></div> <div><input type="submit" value="Save" data-bind="enable: isValid()" /></div> </form>
Create ViewModel
Create a class in JavaScript, taking JSON data to be mapped as parameter, and add isValid as a computed property and finally a save function that posts the JSON-data back to the DogController’s Save method.
var ViewModel = function (data) { var self = this; ko.mapping.fromJS(data, {}, self); self.isValid = ko.computed(function () { return self.name().length > 0; }); self.save = function () { $.ajax({ url: "Knockout2/Save", type: "post", contentType: "application/json", data: ko.mapping.toJSON(self), success: function (response) { alert(response.Status); } }); }; };
Load initial data
Finally you add a JavaScript document ready handler that loads the initial data. Place it below the ViewModel.
$(function () { $.getJSON("Dog/Load", null, function (data) { ko.applyBindings(new ViewModel(data)); }); });
Conclusion
This is probably not the best way, and of course there are lots of stuff you should do. For example, move javascript references to bottom of page, validate the postback and more. But I tried to keep the example as simple as possible.
Download the project here:
I'm just applying this technique for a new project and I got to say it's awesome ! The only problem is the number of magic string in the databind declaration, but I might create an helper for getting rid of this.
Muito bom. Parabéns.
What is “actionResult” here… in the MVC controller.
ActionResult is a class in ASP.NET MVC that encapsulates the result sent to the browser. In the Index-action a ViewResult is actually returned, and the actions returning JSON returns a JsonResult.