Use jQuery and ASP.NET AJAX to build a client side Repeater
AJAX, ASP.NET, JavaScript, UI, jQuery By Dave Ward on June 26th, 2008There was some interesting discussion on Matt Berseth’s blog recently, regarding methods for building and displaying markup on the client side. Though I haven’t posted any examples here before, rendering markup on the client is a technique that I use often and recommend.
By sending only data to the client, you can profoundly reduce the size of what you send and see a substantial increase in performance. You also allow yourself the ability to easily add features like light-weight sorting and paging on the client. This can not only improve your users’ experience, but reduce server load and bandwidth requirements.
To that end, I’m going to walk you through these four steps to effectively implementing a client side Repeater, using ASP.NET AJAX and jQuery:
- Create an RSS Reader page method to return JSON data to the client.
- Call that page method with jQuery.
- Use the returned data to build a table on the client side.
- Improve upon the table creation with a templating plugin.
Creating an RSS reader page method
Because web browsers prohibit cross-domain AJAX functionality, displaying items from an external RSS feed is a good real-world example. To overcome this limitation, our first step is to write a local server side proxy to relay that feed data to the client.
A web service or page method is ideal for this task. I would typically use an ASMX web service, but let’s use a page method here. It’s useful to illustrate how nearly interchangeable the two really are.
[WebMethod] public static IEnumerable GetFeedburnerItems(int Count) { XDocument feedXML = XDocument.Load("http://feeds.encosia.com/Encosia"); var feeds = from feed in feedXML.Descendants("item") select new { Date = DateTime.Parse(feed.Element("pubDate").Value) .ToShortDateString(), Title = feed.Element("title").Value, Link = feed.Element("link").Value, Description = feed.Element("description").Value }; return feeds.Take(Count); }
This page method uses LINQ to parse a few details out of the RSS feed, create an anonymous type with that data, and then return a collection of those anonymous types. By selecting only the data we’re interested in on the server side, we can minimize the traffic between client and server.
In response to my recent deferred content loading post, several of you asked how to limit the results, so I added that this time around. The Take extension method performs this task for us.
Calling the page method with jQuery
On the client side, the first thing we need to do is initiate a request to the page method. We’ll do this with jQuery’s ajax() method:
$(document).ready(function() { $.ajax({ type: "POST", url: "Default.aspx/GetFeedburnerItems", // Pass the "Count" parameter, via JSON object. data: "{'Count':'7'}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(msg) { BuildTable(msg.d); } }); });
When the page loads, this function will perform an AJAX request to our page method, requesting information on the first seven feed items. When the response arrives, a JavaScript function will be called with the response data.
If you are unfamiliar with this jQuery syntax, I have covered it in more detail in two previous posts: Using jQuery to directly call ASP.NET AJAX page methods and Three mistakes to avoid when using jQuery with ASP.NET AJAX.
Building and displaying the table
The page method’s JSON response is going to be similar to this:
[{"Date":"6/5/2008", "Title":"3 mistakes to avoid when using jQuery with ASP.NET AJAX", "Link":"http://encosia.com/2008/06/05/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/", "Description":"Three common problems that I've seen when using jQuery with ASP.NET AJAX, their underlying causes, and simple solutions to them."}, {"Date":"5/29/2008", "Title":"Using jQuery to directly call ASP.NET AJAX page methods", "Link":"http://encosia.com/2008/05/29/using-jquery-to-directly-call-aspnet-ajax-page-methods/", "Description":"An example of how to use jQuery to call an ASP.NET AJAX page method, without using a ScriptManager."}]
The anonymous type in our LINQ query comes through very nicely. The properties that we designated in the page method become keys in an associative array, making it easy for us to work with the data.
To build a table of this data on the client side, we can loop through each element, construct an HTML string, and then assign that string to a container’s innerHTML property:
function BuildTable(msg) { var table = '<table><thead><tr><th>Date</th><th>Title</th><th>Excerpt</th></thead><tbody>'; for (var post in msg) { var row = '<tr>'; row += '<td>' + msg[post].Date + '</td>'; row += '<td><a href="' + msg[post].Link + '">' + msg[post].Title + '</a></td>'; row += '<td>' + msg[post].Description + '</td>'; row += '</tr>'; table += row; } table += '</tbody></table>'; $('#Container').html(table); }
If you think that code looks ugly, that’s because it is. While it works great, I would not recommend this implementation. It will be difficult for you to maintain, and you’ll hope that anyone else forced to maintain it doesn’t know where you live.
Improving the situation with templating
The reason the former code is so ugly is that the presentation and logic are not separated. Even though this is all on the client side, separation of concerns is still an important goal to keep in mind.
To achieve separation, what we really need is a templating solution. As it turns out, there’s a great jQuery plugin called jTemplates, which is perfect for this application.
Using jTemplates, we can create a simple HTML template like this one:
<table> <thead> <tr> <th>Date</th> <th>Title</th> <th>Excerpt</th> </tr> </thead> <tbody> {#foreach $T.d as post} <tr> <td>{$T.post.Date}</td> <td><a href="{$T.post.Link}">{$T.post.Title}</a></td> <td>{$T.post.Description}</td> </tr> {#/for} </tbody> </table>
Since we’re focusing on disentanglement, this template belongs separate file. If we embedded in our JavaScript, we’d be taking two steps forward and one step back. In this case, I saved it as RSSTable.tpl.
With the HTML template created, we can use a couple of jTemplates’ methods to apply the template to the container and then render the page method’s return.
function ApplyTemplate(msg) { // This method loads the HTML template and // prepares the container div to accept data. $('#Container').setTemplateURL('RSSTable.tpl'); // This method applies the JSON array to the // container's template and renders it. $('#Container').processTemplate(msg); }
The rendered result will be identical to the previous, manual method, but the code is much cleaner. At this level of abstraction, I consider this method to be very similar to a client side Repeater.
Conclusion
This is a powerful optimization technique. Identifying overburdened UpdatePanels and replacing them with something like this yields massive performance increases. An order of magnitude isn’t uncommon, in my experience.
One of my sites, WinScrabble.com, was suffering from poor performance due to its primary feature relying on partial postbacks. Because the page was simple and had ViewState disabled, I thought the UpdatePanel would have a relatively minimal impact.
You wouldn’t believe just how wrong I was.
When I removed the UpdatePanel and replaced it with this technique, changing none of the underlying algorithms, requests for 7-8 letter searches ran over 400% faster. I have no doubt that you’ll be able to realize similar improvements in your projects.
In upcoming posts, I’ll go into detail about how to add some client side embellishments: Client side sorting, light-weight paging, and using CSS to improve upon the presentation. So, if you aren’t already subscribed to receive updates via RSS or Email, be sure to do so today.
Try it for yourself: download the source
Similar posts
What do you think? Your comments are welcomed.
I appreciate all of your comments, questions, and other feedback, but please try to stay on topic. If you have a question unrelated to this post, I recommend posting on the ASP.NET forums. If you post there and then contact me with a link to the post, I'll try to take a look at it for you.
If you're replying to an existing comment, please use the threading feature. To do this, click the "Reply to this comment" link underneath the comment you're replying to.

Comments
Another killer article Dave. Nice work.
I am curious – you mentioned before you don’t use UpdatePanels and I see you have found a nice way to use PageMethods without the ScriptManager. So do you use any of the ASP.NET AJAX’s client side stuff? Or has it all been replaced with jQuery?
Matt.
Thanks, Matt.
I do still use UpdatePanels in some scenarios, where they speed up development and performance isn’t critical. In those cases, I’ll use ASP.NET AJAX’s client side events (pageLoad, BeginRequest, EndRequest, etc) in conjunction with jQuery.
That’s about it though. If I have jQuery on the page, I find that it’s much better suited to the presentational work.
Great Post!
Great article, Dave. I like the fact that jQuery is “in the game”.
Althought I was very eager to use UpdatePanels at first, I am very careful now :) My choice is rather calling script services from js.
I’ve too have discovered the jQuery-magic, but I use $.getJSON-method together with a WCF-service, and woaw, what a performance :-) I totally second your opinion in the performance, UpdatePanels are not fast enough.
However, I use the ugly way described above to create the client side html, but now you have presented jTemplates to me, and I will start refactoring at once ;-)
Looking forward to next interesting article!
This is just great, jQuery is a WOW,
Thanks for the posts dave, waiting for the next one.
This should be kicked hundred times Dave! You pointed me some great resources and usages of jQuery.
Great post after few weeks!
Keep it up
Hi Dave. Thank you for your article.
I have an application that uses WebParts and uses the drag and drop of controls with an update panel. For the dragging and dropping of controls in webparts is the update panel okay?
Do you have any articles about using jQuery a WebParts scenario?
My concern is that even if I have ms ajax for webparts with an update panel and I have a gridview that I need to update, it’ll use that update panel instead of jQuery. How can I separate it?
Thanks again for your article.
If you use the Gridview control it has to be processed on the server-side. Which means you have to use a postback to obtain the data of its state, so you would have to use an Update Panel to do this.
If you used a regular HTML table grid, you could update it with jQuery.
Great article!
I am implementing client side repeaters based off the article and I need some help with jTemplates but thier site has been down forever. Do you know where I can get some more information on syntax? Does it only have a for loop? I would like to have a section that states no data was loaded but I don’t know how to write an If statement or if it even has them. I know you are not the jTemplate keeper but no one else is writing about this stuff! Thanks in advance, Jason
There is an {#if} operator. Take a look in the “doc” directory in the jTemplates plugin download. It’s not ideal documentation, but might get you headed in the right direction.
I’ll make sure to add the “no results” case to my improvements in followup posts on this topic. Thanks for mentioning that.
Also my dates print out like this: /Date(1216259889000)/
Any ideas?
I am using c#, .Net, 2.0.
Thanks again,
Jason
Dates are a pain.
It’s not technically very proper, but I almost always convert them to a string on the server side (see the example above). For sorting and filtering, every JavaScript/jQuery plugin I’ve used is able to work with that correctly.
If true Date objects are needed, JavaScript’s Date.parse() is able to parse that format into Date objects.
I’m sure some would take issue with such a “lossy” method of dealing with the data, but I find it works well and is much more simple than the alternatives.
Your dates are printing out like that because you didn’t convert them to a string. You just parsed them as a DateTime.
Thank you for the quick and very accurate responses. I changed my dates to strings and I got the “if” statement working. This is what I used:
{#if $T.d.length == 0}
…
{#/if}
Worked great! Thanks again for the help!
Jason
On the /Date(12319000000)/ issue, I just posted something on Dave’s other http://encosia.com/2008/03/27/using-jquery-to-consume-aspnet-json-web-services/ post…
This ASP.NET DateTime JSON serialization issue I think I have a solution for. I outlined the solution as well as a regurgitated version of this original post at: http://www.overset.com/2008/07/18/simple-jquery-json-aspnet-webservice-datetime-support/
The solution is to pre-parse the DateTime JSON string response from the WebMethod/WebService before jQuery essentially eval()s it:
$.ajax({
// …
dataFilter: function (data, type) {
return data.replace(/”\\\/(Date\([0-9-]+\))\\\/”/gi, ‘$1′);
}
});
This works with jQuery 1.2.6 and .NET3.5 - but appears it might work with .NET2.0.
Schotime has also put a jQuery ajax() wrapper plugin together to help solve this: http://schotime.net/blog/index.php/2008/07/01/jquery-plugin-for-aspnet-ajax-jmsajax/
I am wondering if you left out a crucial line?
The above code never works for me because it has no idea what to do with “msg”
It only works with this line:
Am I missing something? I’ve spent about 2 days trying to get your example to work with no success.
Double check that you’re calling BuildTable(msg.d) in the $.ajax() “success” delegate, and not just BuildTable(msg).
Thanks. I understand your comment but that’s not the root of my question. I have never ever been able to work successfully with any javascript object created from a JSON string return without doing this first:
var evalMatt = eval(’(’ + msg.d + ‘)’);
Also, every single example on the net that I’ve found does that. Example: http://blog.platinumsolutions.com/node/91
What magic am I missing here that doesn’t require you to do an EVAL?
There’s no magic. JSON arrays are native JavaScript objects, so they don’t require any extra translation.
The eval() isn’t doing much there, but eval’ing msg.d has the side-effect of getting you closer to your data.
Have you tried this instead?
var matt = msg.d;
Great post. I have taken this example and applied to an application I am developing. I have run into an issue with jTemplates that I want to see if you have run into. I cannot get jTemplates to work hosted by IIS 6. I get a “expected ;” javascript error in jtemplates source. However in my dev environment hosted via VS or IIS 5 it works fine. Have you seen a problem with jTemplates hosted on IIS 6?
It works for me on IIS6, in IE6. Which browser are you using when you test it on IIS6?
Dave,
I am using IE6, IE7 and FF to view. I decided to host your example source and I get the same problem. I have it hosted on 3 different web servers all running IIS6. But your source still works hosted in IIS5. Any other thoughts?
Are any of those hosted in a location that I can view externally?
Did you ever find a resolution for this issue? I was getting the same thing and finally just gave up. Any ideas?
Darin’s issue was caused by his IIS6 configuration blocking the *.tpl extension.
The easiest workaround is to rename the template RSSTable.htm instead of RSSTable.tpl. Also, make sure to update the setTemplateURL call accordingly.
Thanks Dave, I’ll give that a try.
I just saw your new post about styling a table like this. I’ve been working on implementing this sort of client-side template with a table/grid as well, using the jquery.tablesorter plugin (and pager as well). I’m curious to see how you have tackled it - looking forward to your next post!
Make sure to download the source on my table styling post then. It already has jquery.tablesorter sorting implemented. I just didn’t have time/space to write about it in that post.
For some reason I can’t get it to find my externally defined template. If I define the template as a string and do the following then it’s fine:
$(”#ResultTable”).setTemplate(htmlTemplate, null, {filter_data: true});
However when I define VisitorLookup.tpl as an external file in my js directory then this blows up:
$(’#ResultTable’).setTemplateURL(’VisitorLookup.tpl’);
It fails on this line in TextNode.prototype.get:
var tmp = eval(__a1);
Any ideas?
It turns out that I needed to go into IIS7 and setup a Managed Handler as DefaultHttpHandler for the *.tpl extension. Unfortunately, this also allows users to download the templates if they guess their paths - but that is no worse than users being able to download js files.
Alternatively, if you don’t want to modify your server config, you can use .htm for the template’s extension.
Great tutorial but has it been covered how to provide a “loading” prompt whilst the script is retrieving the data? There is a slight pause before the table is drawn.
If this has already been covered then I apologise.
Great work, keep it up! Ian.
In most cases, I suggest using the technique shown in this post: http://encosia.com/2008/02/05/boost-aspnet-performance-with-deferred-content-loading/
The only caveat is that you must be sure to handle service call failure properly. You don’t want to leave an indefinite loading indicator if the call has failed.
Great article. Thanks for introducing me to jTemplates, it really does make the code more readable. Not a big fan of update panel asp.net AJAX stuff. So this is some really good stuff. Looks like everyone is taking a step to the other side(client side).