View on GitHub

Knockout-server-side-validation

Knockout server side validation

Download this project as a .zip file Download this project as a tar.gz file

Welcome to the knockout-server-side-validation page!

knockout-server-side-validation is simple Javascript library for displaying server side errors in browser where elements are bounded to knockout view model. By default, each message from server is shown next to the element error belongs to. This behavior can be overridden. At this moment, this library enables you very simple integration with ASP.NET MVC server side validation, but if needed, it can be extended to use with some another framework.

If you want to show server side validation errors on client, when using AJAX call, and model is bounded with knockout you should do following:

  1. change way of knockout binding is done

  2. change way of handling validation messages on server

  3. change way of handling validation messages on client

Client side

First add reference to knockout-server-validation. Then, instead of

ko.applyBindings(viewModel, rootNode);

use

ko.applyBindingsWithValidation(viewModel, rootNode);

Server side

For ASP.NET MVC part, we will first add simple extension method

public static class ModelStateExtensions
  {
    public static JsonResult ToKoJsonResult(this ModelStateDictionary modelState)
    {
      return new JsonResult() { Data = new { KoValid = modelState.IsValid, ModelState = modelState.ToKoJSON() } };
    }

    public static object ToKoJSON(this ModelStateDictionary modelState)
    {
      return modelState.Where(x => x.Value.Errors.Count > 0).Select(ms => new
      {
        Key = ms.Key,
        //Value = string.Join(",", ms.Value.Errors.Select(x => x.ErrorMessage)),
        Value = ms.Value.Errors.First().ErrorMessage
      }).ToArray();
    }
  }

Now, we need to change how server handle validation errors. So, first in ASP.NET MVC we need to define attribute

public class KoJsonValidateAttribute : ActionFilterAttribute
  {
    protected bool IgnoreValidation;

    public KoJsonValidateAttribute(bool ignoreValidation = false)
    {
      this.IgnoreValidation = ignoreValidation;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
      if (IgnoreValidation || !filterContext.HttpContext.Request.IsAjaxRequest())
      {
        return;
      }
      var modelState = filterContext.Controller.ViewData.ModelState;
      if (!modelState.IsValid)
      {
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusDescription = "Validation error";
        filterContext.Result = modelState.ToKoJsonResult();
        filterContext.Result.ExecuteResult(filterContext.Controller.ControllerContext);
        filterContext.HttpContext.ClearError();
        filterContext.HttpContext.Response.End();
      }
    }
  }

Now, on action method in your controller, where you are posting data, add attribute to enable validation of data:

[HttpPost, KoJsonValidate]
    public ActionResult Save(MyViewModel model)
    {
      //Save data from model
      //For example, you can redirect to another page when validation passed, or something else, it depends application requirements. This response needs to be handled on client after validateModel returns true.
      return Json(new { redirect = Url.Action("RedirectAction") }));
    }

Client side

After this, we need to add line of code when data is returned from server:

ko.serverSideValidator.validateModel(viewModel, data);

viewModel is knockout model and data is data returned from server from AJAX call.

Dependencies

knockout-server-side-validation has following dependencies: knockoutjs, knockout mapping plugin and jQuery.