Skip to content

Instantly share code, notes, and snippets.

@McNull
Created November 27, 2012 18:29
Show Gist options
  • Save McNull/4156068 to your computer and use it in GitHub Desktop.
Save McNull/4156068 to your computer and use it in GitHub Desktop.
Json Model Binding with Knockout and ASP.NET MVC
namespace System.Web.Mvc {
public class JsonModelBinder : IModelBinder {
private readonly static System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
if (string.IsNullOrEmpty(stringified))
return null;
return serializer.Deserialize(stringified, bindingContext.ModelType);
}
}
}
using System;
using System.Web.Mvc;
using System.Collections.Generic;
namespace Controllers {
public class CustomersController: Controller {
/// <summary>
/// Edit an aspect.
/// </summary>
/// <param name="id">The unique identity of the customer to edit.</param>
/// <returns></returns>
public ActionResult Edit(Guid? id) {
// if the given id is empty, then we will simply edit a new model
if (id == Guid.Empty || !id.HasValue)
return View(new ViewModels.CustomerViewModel{});
return View(); // here we would have some kind of data lookup if a valid id was given
}
/// <summary>
/// Edit a Customer.
/// </summary>
/// <param name="model">
/// The customer to edit, expressed as a view model.
/// </param>
/// <returns>
/// Returns the user to the customers home page if successful, otherwise displays form
/// errors and requests for them to be fixed.
/// </returns>
[HttpPost]
public ActionResult Edit(ViewModels.CustomerViewModel model) {
if (ModelState.IsValid) {
// success
}
return View(model);
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Lightcast.Infrastructure;
namespace ViewModels {
public class CustomerViewModel {
/// <summary>
/// The customer id.
/// </summary>
[Required]
public Guid Id { get; set; }
/// <summary>
/// The customer name.
/// </summary>
[Required]
[DataType(DataType.Text)]
[RegularExpression(@"^(?!.*[ ]{2})(?!.*[']{2})(?!.*[-]{2})(?:[a-zA-Z0-9 \p{L}'-]{3,64}$)$", ErrorMessage = "Invalid name. Names must be between 3 and 64 characters in length, may contain any alphanumeric character and the symbols -', and whitespace only.")]
[Display(Name = "Name")]
public string Name { get; set; }
}
}
@model ViewModels.CustomerViewModel
@{ Html.BeginForm(); }
@Html.LabelFor(model => model.Name)
@Html.TextBoxFor( model => model.Name, new { @data_bind = "value: Name" })
@Html.ValidationMessageFor( model => model.Name )
<br class="space" />
<div class="clearfix right">
<button type="submit">Submit</button>
</div>
@{ Html.EndForm(); }
<script type="text/javascript">
// ----------------------------------------------------------------------- //
// **************************** MODEL BINDING **************************** //
// ----------------------------------------------------------------------- //
// attempt to bind any data we received from the server
var serverData = @(new MvcHtmlString(Model.ToJson()));
// pass any data we received into a new viewModel
var viewModel = new ViewModels.CustomerViewModel( ko.toJS(serverData) );
// apply the knockout binding to the viewModel
ko.applyBindings(viewModel, $("form")[0]);
// attach the jquery unobtrusive validator
$.validator.unobtrusive.parse("form");
// bind the submit handler to unobtrusive validation.
$("form").data("validator").settings.submitHandler = function() {
viewModel.Save( $("form" ) );
};
</script>
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Mvc.Html;
namespace System.Web.Mvc {
public static class HtmlHelperExtensions {
/// <summary>
/// Serializes an object to Javascript Object Notation.
/// </summary>
/// <param name="item">The item to serialize.</param>
/// <returns>
/// The item serialized as Json.
/// </returns>
public static string ToJson ( this object item ) {
return new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(item);
}
}
}
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.Add(typeof(ViewModels.CustomerViewModel), new JsonModelBinder());
}
var ViewModels = ViewModels || {};
ViewModels.CustomerViewModel = function (model) {
return {
Id: ko.observable(model.Id),
/// <summary>
/// The entity identification expressed as a GUID.
/// </summary>
/// <returns type="System.Guid" />
Name: ko.observable(model.Name),
/// <summary>
/// The name of the Customer.
/// </summary>
/// <returns type="System.String" />
Save: function ($form) {
ko.utils.postJson($form.attr('action'), { model: ko.toJS(this) });
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment