Archives / 2008 / July
  • Using client templates, part 1

    Last week, we shipped the first preview for the Ajax work we're doing in ASP.NET 4.0 under the simple form of a simple script file (release and debug versions). This should show how much emphasis this release puts on the client-side. As a matter of facts, I'll use a plain HTML file here instead of an ASPX file to make it perfectly clear that everything here (except for the web service that provides the data) runs on the client.

    One of the scenarios we're trying to improve is updating parts of the page with new data without a postback (in other words, Ajax). That's a scenario you could implement in a number of manners. First, you could put an UpdatePanel control around your server rendering of the data and be done with it. That works, but is a little more chatty than you'd wish. It's all the chattier if you're dealing with a relatively large page with a lot of ViewState (in which case your small partial update pays a tax for the rest of the page that won't get updated). Even without ViewState, HTML isn't necessarily the most compact representation of your data.

    It's usually more efficient, at least in terms of network traffic, to transmit pure JSON data and do the rendering on the client. Now doing that without a proper template engine is clearly not the best use of your time. You could do it either with DOM APIs and a hard to maintain mess of document.createElement and appendChild calls, or you could concatenate strings. The latter solution isn't much easier to maintain (how do you explain your HTML designer how to modify that stuff?) and is quite dangerous, in the same way that building a SQL query using string concatenation is. Nobody in their right mind does that anymore, right? I mean, ...right?

    A good template engine should be highly readable, as close to designable HTML as possible (bonus points if it *is* a version of HTML that can be validated), it must have a good expression language and should perform well.

    Our engine is using markup that can be (but doesn't *have* to be) valid XHTML, it uses JavaScript as the expression language (which means you don't have to learn yet another language), and we're quite pleased with how it performs. Let's have a look.

    The page we're building here is a very simple example of getting some data from a web service (names and photos) and rendering that on the client. Here's what the template looks like:

    <div id="peopleIKnow" class="sys-template">
            <legend>{{ FirstName }} {{ LastName }}</legend>
            <!--* if (Photo) { *-->
            <img sys:src="{{ 'Images/' + Photo }}"
    alt="{{ FirstName + ' ' + LastName }}" /> <!--* } *--> </fieldset> </div>

    And here's what it renders like:

    A few things to notice here.

    The syntax to insert data, be it into text nodes or attribute values, is {{ expression }}, where expression is any valid JavaScript expression. The most common case will be that you want to inject a column of the current data item. For that case, you won't have to use anything like the server-side's Eval("columnName") or anything like Container.DataItem.columnName or $T.row.columnName. You just use the column name and that's it: {{ FirstName }}. This will just inject the value of the FirstName column into the markup. And of course when you need something more complex, like a combination of columns or some additional formatting, you have all the power of JavaScript and the Ajax library at your disposal.

    The alt attribute of the image is one example of that: here, we're combining the first and last name. You could be tempted here to do something like alt="{{ FirstName }} {{ LastName }}". This won't work as the engine only accepts expressions for the full attribute and within text nodes (in the same way that on the server-side, <%# %> blocks have to be the full attribute).

    The src attribute is one of those attributes that you have to prefix with the system namespace sys if you want to bind them (together with id, checked and a few others). There are several reasons for that. First, the template is part of the initial markup of the page. If you used src as usual here, the browser would try to download an image named "{{ 'Images/' + Photo }}", which will of course result in an unnecessary network request, a 404 and some junk in your server logs. Second, an Internet Explorer bug prevents us from reading the binding expression from the DOM (the browser won't give you the actual value that you set, but will always give you what it thinks is the right value, in this case the server-resolved url, which is useless to us). Finally, it can help achieving XHTML compliance (for which, I know, there is a small violation in this template in that the imag tag is missing an actual src attribute, which you can fix -if you have to- by including a src="about:blank" attribute). Some attributes don't accept just any value in XHTML. To summarize, if binding an attribute directly doesn't work, chances are prefixing it with "sys:" just will.

    Last thing is this weird comment block, which we're using to mix JavaScript code into the markup. More precisely, we're doing conditional rendering of the image depending on the existence of the Photo field. There has been much debate over the use of a special comment-based syntax for this. We don't especially like using comments here as we agree that you should ideally be able to remove comments from markup without any impact. We decided to use them anyway because there wasn't a better solution that was still compatible with our XHTML constraint. We did consider admitting both <!--* *--> blocks and something like <script type="application/ms-template"> but that just seemed too verbose and it's rarely a good thing to have two solutions for exactly the same problem. It would be interesting to hear your comments on that, by the way...

    So how do you transform this template into markup? Depends whether you're a component developer, in which case you're going to use the template APIs directly from your component, or if you're an application developer. I'll focus on the latter in this post.

    To render the template with data, you simply instantiate a DataView control and feed it data:

    var peopleIKnowView = $create(Sys.Preview.UI.DataView, {}, {}, {},
    $get("peopleIKnow")); PeopleIKnow.GetPeople(function(results) { peopleIKnowView.set_data(results); });

    In this code, we're using $create to create and initialize an instance of DataView on the "peopleIKnow" div tag, then we invoke the web service, and set the data property on the Dataview control from the callback function of the web service call. That's it.

    Next time, I'll get into more details into what really happens when you instantiate a template, and I'll give some debugging tips.

    The full code for this can be downloaded here: Included script files are subject to the licenses for the Ajax Library and ASP.NET Ajax 4.0 CodePlex Preview 1.

    Part 2 can be found here:


  • Alternating styles in ListView without AlternatingItemTemplate

    ListView (the server-side control), like all repeating data controls in ASP.NET, has an AlternatingItemTemplate, but it would be a shame to have to copy all the markup in the ItemTemplate into AlternatingItemTemplate, just to alternate styles on the items. It's quite likely that only css classes will change between the two, and redundancy is bad <- big scoop here.

    But there is a simpler way. From within any template, you have access to the current index of the row within the whole data set, using Container.DataItemIndex, and within the currently displayed items, using Container.DisplayIndex. This gives us an easy way to alternate styles:

      <li class="<%# Container.DisplayIndex % 2 == 0 ? "even" : "odd" %>">
    <%# Eval("Name") %>
    </li> </ItemTemplate>

    Just define the even and odd classes in your stylesheet and you're pretty much done.

    The full source code for the page is attached below:


  • Using ScriptManager with other frameworks

    ScriptManager is a useful control. It manages script references, removes duplicates, enables localization and debug/release modes, enables script combining and makes client-side component-based development easier (components register their script dependencies with ScriptManager without the page developer having to know those dependencies). But one thing we should have anticipated was that this control would be interesting to developers who wish to use a different framework than the Microsoft Ajax Library.

    Currently, ScriptManager isn't really usable without Microsoft Ajax because it includes the Microsoft library (without a simple way to disable it) and outputs some startup script to the page. We're looking at correcting that in future versions of the framework, but in the meantime I wanted to come up with a workaround.

    The workaround is a simple control derived from ScriptManager and that enables the replacement of the MicrosoftAjax.js reference with a script of your choice:

    <%@ Register Namespace="Bleroy" TagPrefix="asp" %>
    asp:AltScriptManager runat="server"
    FrameworkPath="~/script/jquery-1.2.6.js" />

    Here, we're replacing Microsoft Ajax with jQuery. Being derived from ScriptManager, AltScriptManager benefits from all its features. It just removes the Microsoft Ajax stuff. The resulting markup is:

    <script src="script/jquery-1.2.6.js" type="text/javascript"></script>

    The first thing the control does is set the default value for EnablePartialRendering to false. This suppresses the default reference to MicrosoftAjaxWebForms.js.

    Then, it registers from Init two empty scripts with the type of the ScriptManager and names "AppInitialize" and "FrameworkLoadedCheck". This is a bit of magic that relies on knowledge of the names and types that ScriptManager uses to register its inline scripts.

    Finally, it adds a ScriptReference with the Microsoft Ajax assembly and the "MicrosoftAjax.js" name but with a different path (the value of the new FrameworkPath property). This effectively replaces the Microsoft Ajax script reference with a script of your choice.

    This should broaden developer choice in terms of client framework while keeping the great benefits of ScriptManager. Hope that helps.

    Download it from here:


  • Who's the PC now?

    I saw WALL-E yesterday with my daughter. As usual, Pixar delivers a great, fun movie. Animating a pile of rusty metal and transform it into such a moving character is no small achievement. But there's one thing that I found really curious.

    You know how Pixar is owned by Steve Jobs, right? And in the movie, there is the old WALL-E and the sleek, shiny new EVE. When I saw this unlikely couple, I almost immediately thought about Apple's "I'm a Mac, I'm a PC" ads. And of course, I also thought WALL-E must be the PC, and EVE must be the shiny new Mac. Right? Well, that is until I heard the sound WALL-E does when it reboots (twice in the movie): it's the sound of a Mac.