Processing ModelState errors returned in Json format using Knockout.js

As part of my quest to become a better JavaScript developer I’ve been experimenting with a really neat little JavaScript library called Knockout. For those unfamiliar with Knockout, here’s a very quick overview:

Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model

The rest of this post will pretty much be a brain dump of some of my recent experiments with the Knockout JavaScript library. We’ll take a little look at some typical procedural style usage of JavaScript, and then show how this can be cleaned up using a more declarative style using Knockout.

Returning Model State as Json

To set the scene, I have a small form in the application I’m working on where some complex server-side validation takes place. When this validation takes place, any broken validation rules are transformed into Json and returned to the client.

The implementation that processed the subsequent json result (based on this post) looked a little like this:

Source Code: View

<div id="operationMessage"><ul></ul></div>

Source Code: Scripts

<script type="text/javascript">

   function ProcessResult(result) {

     $("#operationMessage > ul").empty();

      if (!result.Errors) return true;

      $(‘#operationMessage’).addClass(‘error’);

      for (var err in result.Errors) {

       var errorMessage = result.Errors[err];

       var message = errorMessage;

       $(‘#operationMessage > ul’).append(‘<li> ‘ + message + ‘</li>’);

       }

       return false;          

   }

</script>

The function ProcessResult is called subsequent to receiving the response from a server side call using $.ajax(). The result object contains our list of model state errors in json format.

As you can see, the code takes responsibility for:

  1. Ensuring the UL element of #operationMessage is empty (to ensure only the messages from the current result are displayed)
  2. Adding a css class “error” if there are error messages to display
  3. Pulling out each part of the message, and appending it to the DOM

There are a couple of things worth noting here:

  • The function needs to know about the mark-up of the page, and the mark-up to use to display messages
  • The mark-up in the page needs “hooks” in the form of the id, such that the function can locate where to add messages

In essence, the “what” and the “how” of displaying error messages is all contained in one function; if either of these things are to change we risk impacting both.

Let’s see if we can do better.

View Models

The first step in separating out the concerns of our function, is to define the “what” part – what are trying to display? Let’s make that explicit using a view model. Actually, this is pretty simple for this example; we want to display a list of messages. In traditional JS, this is just an array – but since we’ll be hooking into a little Knockout goodness, we’ll use an observableArray:

var viewModel = {

    errors: ko.observableArray([])

};

The observable part is a knockout feature that lets the UI observe and respond to changes. To populate this model, we’ll simply call viewModel.errors(result.Errors) in place of calling ProcessResult.

JQuery Templates

Now we’ve defined our model, we’ll bind to this model using a jquery template. This will form the View, or the “How” part – defining how we want to display our model. First, lets define an element for our template:

<div data-bind=’template: "validationSummaryTemplate"></div>

And then the template itself:

<script type="text/html" id="validationSummaryTemplate, css: { error: errors().length > 0">

   <ul>

     {{each(i, error) errors}}

     <li>

       ${error}

     </li>            

     {{/each}}

   </ul>

</script>

Pretty concise – we’re simply defining the structure of our page in terms of our view model i.e. for each error in the view model, we’ll render a LI tag containing the error message.

Worth noting is the css-binding – remember that we want to add the error class if there are messages to display – that’s how we do it. We could push this logic onto a property of our view model if we like “hasErrors” but since this isn’t complex, or re-used elsewhere in the view, lets keep it here for now.

To apply the binding, we’ll need one final thing. We need to tell knockout to take effect:

ko.applyBindings(viewModel);

Quick Roundup

What have we gained? The “what” and the “how” are now cleanly separated, and the procedural “processing” JavaScript is completely removed. We also no longer need to dig into a JavaScript method if we wish to change the mark-up for our error items (say, to render a table instead of a list).

When writing JavaScript (much like any other language), it’s all too easy to end up with large swathes of procedural code if we aren’t careful in keeping responsibilities focused and separate.  The primary problem that face us with procedural code comes when we try to scale out complexity.

I’ve found Knockout to be a really good enabler for applying patterns such as MVVM, which in turn helps us to keep complexity at bay.

About these ads

About craigcav

Craig Cavalier works as a Software Developer for Liquid Frameworks in Houston Tx, developing field ticketing and job management solutions for industrial field service companies.

Posted on March 20, 2011, in Uncategorized and tagged , , . Bookmark the permalink. 1 Comment.

  1. Thanks for sharing. Knockout really is a fantastic library.

    I’m now using it in a similar way with Rails and server side validations.

    I’m very happy with the reduction in complexity as described in your post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: