ASP.NET User Controls are pretty useful. They allow functional modules of code and markup to be encapsulated in such a way that reuse is convenient and easy, without sacrificing the power or integration of the ASP.NET model. As we move into an era of AJAX-driven websites, this modularity is still very important. Can the user controls that we all know and (mostly) love still help with this encapsulation, despite being engineered before AJAX techniques emerged? I think they can. But at this point in the ASP.NET timeline, user controls are in need of some help.

The Fundamental Problem

With AJAX, more and more content is being dynamically loaded by the client on demand, rather than being included in the original http response. This fundamental change conflicts with the user control’s current usage model of being attached to the control heirarchy during the page lifecycle on the server–either through markup, or using the Page.LoadControl method in code. For user controls to be useful in the world of AJAX and demand loading, we would need to find a way to load them outside of the normal page lifecycle, and use javascript to get the the rendered HTML and inject it into our page. Luckily, this isn’t too difficult to accomplish.

The following example illustrates a basic scenario in which we have a page that uses jQuery to load a user control when a button is clicked. The calling page is pretty simple:

As you can see, all I’ve done in jQuery’s ready event handler is wire up the click event of the button to make an ajax call to a web service. The data result that is returned from the ajax call is then added into the content div on the page. Let’s take a look at the web service that we are calling in that code:

This is a pretty standard WCF Ajax service, which uses a utility class called UserControlUtility by calling its RenderAsString method, which looks like this:

In the helper method above, I’m simply accepting a parameter called path, which allows us to use the LoadControl method in the usual way. If you are worried about the potential baggage of instantiating a Page object for every User Control that is rendered, don’t lose too much sleep over it. A page object that is instantiated like this is pretty lightweight, and doesn’t go through the heavy ASP.NET Page lifecycle that occurs on a normal page load.

This is pretty nifty for simple scenarios, but big challenges arise when the application gets more complicated. What happens when the user control has javascript of it’s own? Well ordinarily you would have a few options. One option that I defaulted to when starting out with jQuery was to write all the JavaScript in the calling page, and just apply it to the user control’s html when it has been loaded. This is not the best solution, because you lose the encapsulation that we were trying to maintain with user controls in the first place. The second solution is to include the javascript within the user control within another jQuery ready handler. This works out much better, because the client functionality gets to be bundled with the markup for clean encapsulation. Additionally, the included javascript will be excuted when the control is rendered on the parent page, thanks to jQuery. But has this solved all of our problems? Not quite.

Mo Javascript, Mo Problems

To illustrate how problems can arise with that last solution, let me give an example. Say you are developing a real-time stock-screening application. In this application, you have a user control called StockItemRow.ascx that had quite a bit of javascript associated with it. You also have a page called Screener.aspx that periodically polls a web service for matching stocks, and adds those stocks to the grid via a rendered instance of StockItemRow.ascx. And suppose the user control had a good deal of javascript bundled with it, and also a few nested user controls of its own (with their own javascript, of course). What were to happen if you dynamically added 50 or 60 rows over a few minutes? You may see what I am trying to get at here.

The problem is that the JavaScript is being loaded over and over on each successful new request for data, simply because it is bundled inside the rendered user control. As you load more and more data onto the page, this becomes a bigger and bigger waste. Plus, unless you write your javascript very carefully, each new dynamically loaded user control could end up applying it’s javascript to other user controls that have already been loaded. Yuck! In order to solve these problems, it is going to take a little more work.

The first issue we need to solve is the repititious loading of unnecessary javascript. To do this, we need to separate it out from the user control into it’s own js file. Some may argue that we are losing encapsulation here, but I disagree. I think just if an aspx page can have both a file for markup and a codebehind file, then a user control can have both a markup file and a js file (and it’s codebehind file, for that matter). After we have separated it out, we have freed ourselves to be able to load the javascript file once, while still rendering the user control multiple times.

But just separating the javascript out doesn’t solve our problems. We need to somehow “register” a single instance of javascript on the page, and have any dynamically loaded user controls use just that instance. Additionally, we need to make sure that the javascript is capable of being applied to individual user controls, without affecting other user controls that have already been wired up and loaded on the page.

Enter jQuery.DynamicLoader

jQuery.DynamicLoader is a simple jQuery plugin I wrote that allowed a parent page to dynamically load User Controls and their corresponding script files on demand. Here is the way it works:

You reference jQuery.DynamicLoader on your parent page.

Create an ajax service that renders user controls, similar to the example I showed earlier

Anytime you want to load a user control on that page, call $.dynamicLoader.loadUC() with the appropriate options. This will fetch the rendered user control, and its corresponding javascript file. If the javascript is being loaded for the first time, DynamicLoader will register that instance as the singleton for all subsequent user controls of that same type.

The javascript instance is then invoked with the rendered user control as its UI context.

The project contains a single page Default.aspx, and two user controls, TableWidget.ascx and CellWidget.ascx. The purpose of the project is to demonstrate a page intitally with no content, and how we can dynamically load several tiers of user controls, each with their own scripts. We start from a single button on Default.aspx that will dynamically load a new TableWidget every time it is clicked. Inside each TableWidget is a button gets wired up to load its own user controls, this time CellWidgets. Each CellWidget has its own javascript that needs to execute as well.

Here is how the first button is wired up with jQuery:

As you can see, it is calling DynamicLoader’s loadUC function, which takes a few options: ucName is the path to the user control to be loaded, queryString allows you to pass parameters to your UserControl to help render it on the server, and eventBindings allows you to handle events that are fired within the usercontrol.

As I mentioned earlier, the javascript in your user control needs to be registered before it can be used. Don’t get scared off now, it’s only two extra lines of code:

We have a standard jQuery ready handler, and inside that we call DynamicLoader’s registerUC function. This will only be loaded once, even if multiple TableWidgets are loaded afterwards. Also notice the event triggers. You can create as many different types of events as your heart’s desire, as long as the parent knows the name of the event (and references it in the eventBindings option). I’ve included ready, busy, unbusy, and finished in the default options. The ready event is one that I consider critical, because it is the event that the parent will use to attach the user control to the page.

You can see that there are buttons on the CellWidget that do some trivial javascript actions, and also a button that demonstrates an event being monitored by the parent user control.

Room for Improvement

DynamicLoader is more of a proof concept than a full-fledged plugin, and there are several areas in which it needs to be improved:

The event chaining needs some work. I haven’t really tested it with events that bubble more than two layers up.
Right now it doesn’t look like jQuery’s $.getScript is caching the scripts. I’d like to rewrite a version of getScript that does.
The registration system is very rigid at this point. It expects you to pass in a user control’s path, and the script needs to register itself with that exact path as its key (without the extension).
So there you have it. This technique allows you to treat your User Controls as neatly encapsulated modules that are loaded and configured on demand. Plus, there is no limit to nesting your user controls, and they will load efficiently and within their own context. Finally, you don’t have to break communication with your user controls. The event binding allows a separation of concerns, while still being able to act on important things that happen within the user control.

I hope you find this technique useful, and please let me know if you have suggestions or improvements!

For those that know me, it goes without saying that I’ve fallen head over heels for jQuery. It just makes working with javascript much easier and cleaner than ever before, and opens the door to so many new possibilities that were just to cumbersome even a few years ago. Of course, with new possibilities always comes new challenges. One of those important challenges is client side templating.

For me, there was an evolutionary process before getting to the point where I realized client side templating was important. It all started out in the olden days of using ASP.NET Web Controls. With Web Controls, the idea was pretty simple: You bind your control to a datasource, and any events you wanted to take action on in that control would require a postback to the server. These postbacks were hugely interruptive, especially when performing lots of different manipulations on a single page. So when “Atlas” and the UpdatePanel came along, it looked to be exactly what we needed. We build pages in the exact same way we always did, slap an UpdatePanel around the whole thing, and magically all our problems would go away. Well as we’ve all found out by now, it’s not that simple. The heaviness and waste of an entire page lifecycle on each async postback, combined with the limitations of the postback model itself made it useful only in certain situations (like removing the flicker from an existing website with heavy postbacks).

When I first started using jQuery, I quickly realized that I could circumvent the whole postback model in favor of ajax and REST services, but I still wasn’t ready to give up the WebControls like ListView and GridView that I’ve used for so long. That was when I had the idea of calling a service to render a UserControl on the server, and pass back the html to insert onto my page. After googling “render user control service”, I quickly found out that I wasn’t the only one thinking of this idea, and off I went to get it working.

After using it for a few scenarios, the drawbacks of this approach started to be more apparent. The first drawback was getting access to the actual data. Sure, you have rendered view, but what if you wanted to do more with a particular record in that view, like show it on a google map? Do you try and extract what you need from the rendered html, or do you have a separate ajax call to get just the data? Another challenging drawback was control state, like scroll location or pagination. For example, if you render a UserControl with a ListView and PagerControl on it, you get paging buttons that are absolutely useless. I got around this by using jQuery to intercept the click events of those page buttons to call the rendering service, but these issues had me feeling like I was hacking the solution just to get the control and accessibility I needed. Finally, there is the bloat factor. Yes, this solution is much much lighter than the UpdatePanel + postback model, but not nearly as light as just passing the data down as JSON and rendering that data on the client.

Which brings me to the second-to-last step in the journey to client templates: rendering the data yourself with jQuery. Rick Strahl has a good blog post of this technique, but I’ll give an example of my own. You simply start with a block of html on your page that will serve as your template, like the following markup:

After you pull your JSON data from the web service, you clone the html for each record and inject the appropriate data, adding event handlers as you go:

This approach has a lot of things going for it — bandwidth efficiency, lightweight processing, and templates that are understandable. However, once you’ve coded a couple of these scenarios, two things become obvious. The first is that you are writing a hell of a lot of repetitive code just to match the correct element in the template with its value. The second thing is that you have to write lots more code if you want to do any kind of synchronization between two views that share the same data. How can we solve these two problems?

Chain.js is a jQuery plugin that aims to solve the templating and data synchronization shortcomings that I mentioned above. My favorite demo synchronizes two lists together, which really shows the simplicity and power of Chain.js in both templating and synchronizing two views dynamically. You start with the following markup:

We have two lists here, each with a template called “item”. The aim of the demo is to populate the “persons” list with a dataset, and then link the “filtered” list to show the items that have been filtered out of the first list. Here is the code that makes it all happen:

In the above code, the items plugin is initialized on the persons list with some data, and then .chain() is called to automatically bind the data to the template inside of the persons list. The default Chain.js data binder looks for classNames that correspond to the property on the JSON element. Chain.js automatically looks for the first item inside of the parent element to use as the template, but you can configure precisely where your template is with the anchor option. Next, a handler is setup on input’s keyup event so that we can use filter function to filter the list of items on every keystroke. Finally, we take our second list and link it to the collection ‘hidden’ on our first list, and call chain to initiate the data binding.

Chain.js is a great concept and great code, and it works very well in these demos. But it is still a project in it’s infancy, and that is apparent when you try to scale up the amount of data you are binding to, and the amount of views that are linked to the data. The performance literally grinds to a halt, even on the fastest machines.

Solving the current limitations of Chain.js

When analyzing the source code for Chain.js, I realized I could do something fairly simple right off the bat to speed up data-binding: use innerHTML instead of jQuery’s clone() method to create each templated item. The internals of the binding function “$update” in Chain.js look something like this (as of version 0.1):

Here is the modified code that uses innerHTML to create all the items ahead of time (without jQuery’s clone), and the loop picks each item out of the list for data binding:

Just this change alone made data binding about twice as fast in my testing. But with large datasets, that wasn’t enough of an increase. So I dug some more and I identified another issue: when synchronizing a series of views, the collections that you subscribe to are filtered with jQuery. So therefore, your master view is always required to create a corresponding DOM element for each data item. This means that if you have a thousand data items, but you only want your views to render and show a subset of those thousand items, then you still have to create a master view, which in turn requires a DOM element for each data item. That is a ton of extra work! So I set out to modify the code so that a master object is created that doesn’t have any dom elements that correspond to the data. Then, all other views are a linked to this object. But without the DOM, how are we supposed to use jQuery to filter our collections? The answer is, we don’t.

Taffy DB is a lightweight javascript library that acts as a thin data layer on the client. This is exactly what is needed to quickly select the elements needed for the subscribing views. By circumventing the creation of dom elements and jQuery selectors to build the collections, performance increased approximately four-fold beyond the innerHTML modification! Unfortunately, the implementation of Taffy DB required changes in many areas of Chain.js, so I do not have any code samples. But if there is demand, I may either post my modified code, or coordinate with the author of Rizqi Ahmad, the creator of Chain.js, to implement some of these ideas.

Other Client Template Libraries

It is pretty obvious that many developers see client templating as important going forward. This is evident in the amount of Client Template Libraries that are cropping up. Just recently, Microsoft released a preview of ASP.NET AJAX 4.0, which includes client-side template rendering. This seems promising, but I haven’t had much time to play around with it. There’s also jTemplates, PURE, and LightningDOM, although they are more geared towards just client side templating, rather than trying to tackle synchronization (like Chain.js and ASP.NET AJAX 4.0). If I’ve missed any other libraries, please let me know!