Web API playing well with JQuery Templates

by DotNetNerd 1. May 2011 21:38

Since my last blogpost about Web API Glenn Block appeared on Hanselminutes so it seems to be hot stuff at the moment. Having already written part of this blogpost, as it was actually part of the last post before I decided to break it in half, it seems a good time to finish it and get it out there. So building on my last post I will also take a look at how Web API plays along with JQuery and the new JQuery templates.

A word on caching

First off one of the things I learned is that you need to care about being explicit in reguards to caching. Crome and Firefox see Ajax calls as being non-cachable, but IE sees it as any other request. So I ran into a scenario where IE failed to get data after I had visited the URL of the Resource directly – until I cleared the browser cache. I then chose to handle caching explicitly, and the problem went away. So in my case I chose to set the cache control header to NoCache so I always get fresh data – but pretty often I would probably cache for a certain amount of time, like illustrated in the code that is commented out. Even better could be to implement a conditional get, which is covered very well by Pablo Cibraro in this blogpost. Lastly setting cache=false in JQuery also does the trick, but that would not give me an excuse to show how it is done with Web API, so here you go :)

[WebGet(UriTemplate = "{id}")]
public HttpResponseMessage<List<Product>> Get(int id)
{
    var items = _repository.FindProductsFromCategoryById(id);   
    var response = new HttpResponseMessage<List<Product>>(items);
    result.Headers.CacheControl = new CacheControlHeaderValue() { NoCache = true};
    //result.Headers.CacheControl = new CacheControlHeaderValue()
    //  {
    //      Public = true, MaxAge = new TimeSpan(0,0,1,0)
    // };
    return response;           
}

Another new friend - JQuery templates

Most web developers who have worked with Ajax have probably tried building part of a UI by concatenating strings of html. It is hardly ever pretty, and with just a bit of complexity it quickly becomes painful. Thankfully JQuery now has its own templating plugin, which can be uses via Microsofts CDN here http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js

I wont try and battle the folks at JQuery in writing documentation, as they have already done a good job. So I will just show a quick example. A very straight foreward template could look like the sample below. As you can see all you need to get started is a script tag with type text/html and then you can write you template using the ${} syntax as placeholders for values.

<script id="productTemplate" type="text/html">
<li>
<h3>${ Name } (${ Id })</h3>
<p>Price: ${ Price }</p>
</li>
</script>

In order to bind data to this template you can do a couple of things. You can either bind directly using one line of code, or you can create a cached template for reuse and bind that.

$("#productTemplate").tmpl(value).appendTo("#products");
or
$("#productTemplate").template("productList");
$.tmpl("productList", data).appendTo("#products");

Using the shorthand syntax in JQuery for grabbing JSON from a service we can then simply grab and bind the data as cleanly as this.

$("#productTemplate").template("productList");

$.getJSON(
    "products/12",
    function (data) {
        $.each(data,
            function (index, value) {                  
                $.tmpl("productList", value).appendTo("#products");
            }
        );       
    }
);

Whats the word - eeh verb. For now it is Post

Going the other way and submitting data back to the resource, can be done using http post. So to align with the previous sample a simple method on the resource could be written like this sample shows. As you can see it nicely sets the HttpStatusCode and the location header.

[WebInvoke(UriTemplate = "", Method = "POST")]
public HttpResponseMessage<Product> Post(Product item)
{
    _repository.Add(item);
    var response = new HttpResponseMessage<Product>(item);    
    response.StatusCode = HttpStatusCode.Created;
    response.Headers.Location = new Uri("Products/" + item.Id, UriKind.Relative);
    return response;
}

Now we need a form with some data to be posted, and since I don’t want to bore you with the details let’s look at using a basic html form like this one.

<form>
    <input type="hidden" id="Id" name="Id" value="10" />
    <input type="text" id="Name" name="Name" />
    <input type="text" id="Price" name="Price" />
    <button type="submit">Here</button>
</form>

Oddly enough there is no shorthand for doing a post and getting back JSON in JQuery, but thankfully it is still only a few lines of code code. To be honest I often use this approach anyway, so I can have a function that handles any error that might occur. What we are doing is handeling the submit event, where we serialize the form and do an Ajax post instead of a regular post, which would reload the page. Web API knows the application/x-www-form-urlencoded format so it handles binding to the Product model object.

$("form").submit(function () {
    $.ajax({
        type: "POST",
        url: "products", 
        data: $(this).serialize(),
        success: function (data, textStatus, jqXHR) {
            $("#productTemplate").tmpl(data).appendTo("#products");
        },
        error: function (xhr, status, error) {
            alert(errorThrown);
        },
        dataType: 'json'
    });
    return false;
});

The application/x-www-form-urlencoded format is really as simple as "Id=12&Name=test&Price=10" – to do the same as the form does in the sample. So building the data payload manually is no problem either.

Looking to the future

An interesting alternative to using JQuery that is comming up is DataJS, which among other things enables you to use HTML5 features for doing caching and prefetching. For now it only works with OData, but according to the codeplex site, it is supposed to support OData AND JSON. There are signs that they will be tailored to fit together nicely, so I for one look forward to getting my hands dirty.

Comments (5) -

Niels Brinch
Niels Brinch Denmark
5/8/2011 5:27:02 AM #

Finally our paths, technology wise, have crossed! You have certainly strayed far during the last few years Smile

Using JQuery Templates I find it a welcome separation of UI from logic - however, I also find that it has limitations. You cannot do 'anything' in a JQuery Template, and some times, that's exactly what I need ... then I degrade to returning html directly from the WebMethod or let JQuery create the needed html based on json...

So JQuery Templates seems not to be something you can quite simply choose and never look back, but it can be used for many scenarios.

DotNetNerd
DotNetNerd Denmark
5/8/2011 11:43:35 AM #

But you can have logic in your templates! The samples here are just very basic but you can do if statements, loops as well as call methods. I can do a post on it later, but there are some good samples out there...

Niels Brinch
Niels Brinch Denmark
5/8/2011 12:55:26 PM #

But the target (my target anyway) with the template was to separate the logic from the presentation - but I should definitely check out the more advanced possibilities with templates. Would you say you can do the same with a JQuery Template as you can with an XSLT?

DotNetNerd
DotNetNerd Denmark
5/8/2011 6:27:47 PM #

Well one runs serverside and the other clientside, so I really would not compare them. But in reguard to just pproducing markup you can do everything.

DotNetNerd
DotNetNerd Denmark
5/8/2011 8:44:00 PM #

but seperating script and markup is more a matter of techniques i think. Is there some specific kind of separation you are thinking about Niels?

Who am I?

My name is Christian Holm Diget, and I work as an independent consultant, in Denmark, where I write code, give advice on architecture and help with training. On the side I get to do a bit of speaking and help with miscellaneous community events.

Some of my primary focus areas are code quality, programming languages and using new technologies to provide value.

Microsoft Certified Professional Developer

Microsoft Most Valuable Professional

Month List