Progressive enhancement and Knockoutjs

In these series of posts, I will show an approach that brings the ideas of Progressive Enhancement design into the Knockoutjs applications. Progressive enhancement is a strategy for web design that emphasizes accessibility, semantic HTML markup, and external stylesheet and scripting technologies.In simple words, progressive enhancement is the separation of HTML, CSS and JavaScript. Knockout is a JavaScript library that helps you to create rich, responsive user interfaces with a clean underlying data model. knockout.js helps you simplify dynamic JavaScript UIs using the Model-View-ViewModel (MVVM) pattern.

Compare to a few years ago, Browsers make a remarkable progress in terms of performance and there are lots of Javascripts platforms and libraries that make client side development much easier. Such improvements turns the Progressive Enhancement design less favorite, and nowadays many don’t believe in it. Jake Archibald, wrote a nice article here mentioning a dozen of reasons that Progressive Enhancement is still important. Like Jake, I think using PE brings many benefits on the table. When we talk about Progressive Enhancement, we don’t talk about a few percentage of users that their browsers don’t support advanced features, instead we talk about a design principle. Something that makes the life easier in the maintenance phase. Unfortunately, currently there is no clear method to use knockout and PE design together. In this post, I will try to make a bridge between them.

The idea is simple. For non AJAX requests, the server must return a full HTML page, on the other hand, if the request is an AJAX request, then the server must return a JSON response. In the client side, the knockout library will be activated in the first visit, its Models and ViewModels will be made and the next interactions with the server will be handled by AJAX request and JSON data-types. In this way, web spiders or clients without javascript, receive HTML pages, and clients with modern browsers see a modern Single Page Application.

In server side, using ASP.NET MVC, it is very simple. In each Action, we can check the request type, if the request is not an AJAX request, then the Action renders a View that contain a complete HTML page and sends it to the client. Alongside the HTML, the View can contain a hidden input that keeps the JSON data. Knockout clients can use that data to create Models and ModelViews. For AJAX requests, the server will send the data in JSON format. For Views and templates, we can also use Razor view engine.

In the client side, we can parse the hidden input, create the Models and ViewModels and bind the data to the HTML. Sounds easy in words, but in reality there are problems. The main issue is the fact that knockout doesn’t respect the generated HTML from the server. For inline bindings, We can accept the overhead of rewriting their values. But bindings that generate HTML like template or foreach have issues. One solution would be deleting the server-side generated HTML for each template or foreach binding, before applying the binding.?! But it is not very convincing. The ideal is, knockout uses the current generated HTML tags in its foreach and template bindings. Without regenerating the HTML in the client side, our Progressive Enhancement design becomes perfect.

Current template and foreach bindings of the knockout don’t satisfy our expectation. The solution in such situations is implementing custom bindings. We need a special template binding that first, provides a mechanism to match the current HTML items with the knockout ViewModel items, second, it must be able to distinguish between the server-side generated HTML and client-side generated HTML, third, it must contain the complete functionality of the original template binding. My solution is annotating the HTML with the special data-attributes in server side. For each generated HTML template, such attributes specify the key name and key value of the underlying data. The binding reads the attributes and uses them to match them with the ViewModel items. If it finds a match, it doesn’t render the template for the matched item. After any match, it deletes the annotated attributes, in order to prevent them to be used in the next updates. The binding can be used as follows:

<ul data-bind="petemplate: { name:'toDoListItem-template', foreach: todos}" data-templateId="data-todoItemId">

It looks like the original template binding except two difference. First, it doesn’t work with anonymous templates. It means that defining the template inside the ul tag in the above sample is not possible. Second there is a new HTML attribute. “data-templateId”. It is the attribute that will be used by the peTemplate to find and match the current HTML tags with the knockout viewmodel items. Its value is the name of an attribute that will be used in child tags to specifies the key of the child. Its value must be in the format “{data-{key}}” where the key is the name of the key field in the data model. In the server side, the HTML will be generated as follows:

 <ul data-bind="petemplate: { name:'toDoListItem-template', foreach: todos}" data-templateId="data-todoItemId">
        @{
            if (Model.Todos != null)
            {
                foreach (var item in Model.Todos)
                {
                    string checkedStr = item.IsDone ? "checked" : string.Empty;
            <li data-todoItemId="@item.TodoItemId">
                <input type="checkbox" @checkedStr data-bind="checked: isDone" />
                <input class="todoItemInput" value="@item.Title" type="text" data-bind="value: title, disable: isDone, blurOnEnter: true" />
                <a href="#" data-bind="click:
                        $parent.deleteTodo">X</a>
                <p class="error" data-bind="visible:
                        errorMessage, text: errorMessage"></p>
            </li>
                }
            }
        }
    </ul>

Most of the code of the peTemplate comes from original template bindings. Using the peTemplate, we can use the server-side generated HTML in knockout applications. The approach has a bandwidth overhead in the first load of the pages, since the server sends HTML plus JSON data. But it happens only in the first load and the benefits of using Progressive Enhancement is much higher than that overhead. You can find the bindings source code here. There is a simple sample that uses the binding here. In the next posts, I write more about the knockout and progressive enhancement.


No Comments

Post Reply