Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

October 2009 - Posts

JavaScript class browser: once again with jQuery

(c) 2004 Bertrand Le Roy I’ve already posted twice about that little class browser application. The first iteration was mostly declarative and can be found here:
http://weblogs.asp.net/bleroy/archive/2009/09/14/building-a-class-browser-with-microsoft-ajax-4-0-preview-5.aspx

The second one was entirely imperative and can be found here:
http://weblogs.asp.net/bleroy/archive/2009/10/15/entirely-unobtrusive-and-imperative-templates-with-microsoft-ajax-4-preview-6.aspx

This new version builds on top of the code for the imperative version and adds the jQuery dependency in an attempt to make the code leaner and simpler. I invite you to refer to the imperative code (included in the archive for this post) and compare it with the jQuery version, which shows a couple of ways the Microsoft Ajax Library lights up when jQuery is present.

The first thing I want to do here is convert the plain function I was using to build the browser’s namespace and class tree into a jQuery plug-in:

$.fn.classBrowserTreeView = function (options) {
  var opts = $.extend({},
$.fn.classBrowserTreeView.defaults,
options); return this; };

That plug-in will have two options: the data to render (which will default to the root namespaces in the Microsoft Ajax Library), and the node template selector (which will default to “#nodeTemplate”):

$.fn.classBrowserTreeView.defaults = {
  data: Type.getRootNamespaces(),
  nodeTemplate: "#nodeTemplate"
};

For the moment, as you can see, this plug-in does nothing. We want it to create a DataView control on each of the elements of the current wrapped set. We will do this by calling into the dataView plug-in.

You may be wondering where this plug-in might come from. Well, that’s the first kind of lighting up that the Microsoft Ajax Library’s script loader (start.js) will do in the presence of jQuery: every control and behavior will get surfaced as a jQuery plug-in, and components will get added as methods on the jQuery object. This is similar to what I had shown a while ago in this post, only much easier:
http://weblogs.asp.net/bleroy/archive/2009/05/04/creating-jquery-plug-ins-from-microsoftajax-components.aspx

For example, we can write this in our own plug-in to create DataView components over the current jQuery wrapped set:

return this.dataView({
  data: opts.data,
  itemTemplate: opts.nodeTemplate,
});

Now we can wire up the itemRendered event of the data view and start enriching the markup that the DataView control rendered for each data item. First, let’s get hold of the nodes in the rendered template and wrap them:

var elt = $(args.nodes);

Then, if the current node is representing a namespace, we want to hook up the expansion button’s click event so that it toggles visibility of the list of children, and we want to “unhide” the button itself (it has a “hidden” class in the default markup):

if (Type.isNamespace(args.dataItem)) {
  elt.find(".toggleButton").click(function (e) {
    e.preventDefault();
    return toggleVisibility(this);
  }).removeClass("hidden");
}

You can see here that we’re taking advantage of chaining.

Next thing is to set-up the node link itself. We start by inhibiting the link’s default action. Then we set the text for the link, and finally we set the command that will bubble up to the DataView when the link gets clicked:

elt.find(".treeNode").click(
function (e) {
e.preventDefault();
return false;
}) .text(getSimpleName(args.dataItem.getName())) .setCommand("select");

Here, I’m using a small plug-in to set the command:

$.fn.setCommand = function (options) {
  var opts = $.extend({},
$.fn.setCommand.defaults, options); return $(this).each(function () { $.setCommand(this,
opts.commandName,
opts.commandArgument,
opts.commandTarget); }); } $.fn.setCommand.defaults = { commandName: "select", commandArgument: null, commandTarget: null };

I’m using $.setCommand here, which does get created by the framework for me, but I still need to create that small plug-in to make it work on a wrapped set instead of a static method off jQuery. I’ve sent feedback to the team that setCommand and bind should get created as plug-ins by the framework and hopefully it will happen in a future version.

The last thing we need to do here is to recursively create the child branches of our tree:

elt.find("ul").classBrowserTreeView({
    data: getChildren(args.dataItem)
});

This just finds the child UL element of the current branch and calls our plug-in on the results with the children namespaces and classes as the data.

And this is it for the tree, we can now create it with this simple call:

$("#tree").classBrowserTreeView();

The details view rendering will only differ in minor ways from the code we had in our previous imperative version. The only differences is the use of jQuery to traverse and manipulate the DOM instead of the mix of native DOM APIs and Sys.get that we were using before. For example,

args.get("li").innerHTML =
args.dataItem.getName ?
args.dataItem.getName() :
args.dataItem.name;

becomes:

$(args.nodes).filter("li").text(
args.dataItem.getName ?
args.dataItem.getName() :
args.dataItem.name);

Notice how jQuery’s text method makes things a little more secure than the innerHTML we had used before.

Updating the details view with the data for the item selected in the tree is done by handling the select command of the tree from the following function:

function onCommand(sender, args) {
  if (args.get_commandName() === "select") {
    var dataItem = sender.findContext(
args.get_commandSource()).dataItem; var isClass = Type.isClass(dataItem) &&
!Type.isNamespace(dataItem); var childData =
(isClass ? getMembers : getChildren)(dataItem); var detailsChild =
Sys.Application.findComponent("detailsChild"); detailsChild.onItemRendering =
isClass ?
onClassMemberRendering :
onNamespaceChildRendering; detailsChild.onItemRendered =
onDetailsChildRendered; detailsChild.set_data(childData); $("#detailsTitle").text(dataItem.getName()); $(".namespace").css(
"display",
isClass ? "none" : "block"); $(".class").css(
"display",
isClass ? "block" : "none"); $("#details").css("display", "block"); } }

Not much change here from the previous version, again, except for the use of jQuery and some chaining.

And that is pretty much it. I’ve made other changes in the script to make use of the new script loader in the Microsoft Ajax Library but that will be the subject of a future post.

Hopefully, this has shown you how the Microsoft Ajax Library can light up with jQuery. The automatic creation of plug-ins feels very much like native jQuery plug-ins and brings all the power of client templates to jQuery. Once we have bind and setCommand plug-ins as well, the Microsoft Ajax Library may become a very useful tool to jQuery programmers just as much as jQuery itself is a very useful tool to Microsoft Ajax programmers.

The code can be found here:
http://weblogs.asp.net/blogs/bleroy/Samples/ClassBrowserWithjQueryUpdated.zip

Update: fixed a problem in Firefox & Chrome.

How to render the same template on the server and client with minimal redundancy

(c) 2005 Bertrand Le Roy

Last week, I wrote a post about how the new Microsoft Ajax Library Preview 6 made it a lot easier to write unobtrusive and imperative data-driven applications. Because for the previous preview, I had written a cool little class browser using a declarative style, I thought it would be nice to rewrite this in a completely imperative way. The mistake I made though was to call it unobtrusive. Never mind that ‘unobtrusive’ is a perfectly well-defined word that actually existed way before JavaScript. ‘Unobtrusive JavaScript’ has a very specific meaning that people feel strongly about. To be worthy of that label, an application must basically conform to (at least) those two requirements:

  1. Markup and behavior are strictly separated. That means no DOM-0 event handlers, no custom attributes or tags, and even no microformats imo.
  2. Graceful degradation / progressive enhancement. This means that the application’s script is only used to improve what would work without script, in other words that the application is entirely usable without script.

While my little sample strictly conformed to (1), it didn’t conform to (2). Not because I’m too dumb or ignorant, mind you, but because for this application, it didn’t make any sense at all: the application’s whole point is to display client-side script objects. The server does not have the first clue about the data that needs to be rendered. Which makes it impossible for anything to render without script. Which in turn triggered some unpleasant comments on the post: this was not really unobtrusive JavaScript in the full sense of the term. Not the library’s fault though, just my own for using the wrong example.

The right example

So I thought the best thing to fix this is to provide a more relevant example, one where the server could actually be a fallback scenario.

The new sample code is a fairly simple master-details view on a silly data set: jedi data. We have a WCF web service that is returning a list of jedis and their associated data, which the application can render on the server-side or on the client-side.Jedis Once you  have data that is available from both the server and client sides, your best and simplest tool to achieve progressive enhancement is the plain <a> tag. You can build the links in your application so that without script, they do something meaningful:

<a href="?jedi=all" id="expandButton">+</a>

What you see above is the + link on the top-left of the screen that will expand the list of jedis. To make it work client-side instead of the server-side, you use script to add a click handler that suppresses the default behavior of the link and replaces it with the equivalent client-side action:

Sys.UI.DomEvent.addHandler(
Sys.get("#expandButton"), "click", function(e) { e.preventDefault(); jediList.fetchData(); return false; });

That’s fairly easy and has been possible since, well, I’m not sure but it’s been a looong time.

Now there’s the templated rendering. Rendering the same thing from the server and the client without repeating oneself too much is not as simple. The key to it is to render the server template with an empty data item and then to use the result of that as the client template.

<ul id="jediList"
<%if (!isDetails) { %> class="sys-template"<% } %>> <%var jedis = !isDetails ? new List<Jedi>() {new Jedi()} : new JediService().GetJedis(); foreach (var jedi in jedis) { %> <li>
<
a href="?jedi=<%= jedi.Name %>">
<%= jedi.Name%>
</
a>
</
li> <%} %> </ul>

This way, there is only one template, only one version of the markup, that we are using on both the server and client sides. When rendered from the server with the actual data set, we get the list right away, and the browser just displays it (and search engines can see the list as well, something you can’t achieve with pure script). When rendered with the dummy dataset, we get the following:

<ul id="jediList" class="sys-template">
  <li><a href="?jedi=all">all</a></li>
</ul>

This markup can be used as a template on the client-side by this code:

var jediList = Sys.create.dataView("#jediList", {
  dataProvider: "JediService.svc",
  fetchOperation: "GetJedis",
  autoFetch: false,
  itemRendered: function(sender, args) {
    var link = args.get("a");
    var dataItem = args.dataItem;
    link.innerHTML = dataItem.Name;
    Sys.UI.DomEvent.addHandler(
link, "click", function(e) { e.preventDefault(); details.set_data(dataItem); return false; }); } });

The details view is built on pretty much the same principle. The main difference is that it does have additional markup to delimit the fields that we’ll want to set dynamically. Here’s how it renders with the dummy data:

<div id="details" class="sys-template">
    <span id="jediName"></span>
    owns a
    <span id="jediLightSaber"></span>
    lightsaber and is on the
    <span id="jediSide"></span>
    side.
</div>

All the itemRendered handler has to do then is fill in the blanks:

var details = Sys.create.dataView("#details", {
  itemRendered: function(sender, args) {
    args.get("#jediName").innerHTML =
args.dataItem.Name; args.get("#jediLightSaber").innerHTML =
args.dataItem.LightsaberColor; args.get("#jediSide").innerHTML =
args.dataItem.DarkSide ? "dark" : "light"; } });

So what do you think?

Here’s the code (by the way, I’m using the Microsoft CDN in there):
http://weblogs.asp.net/blogs/bleroy/Samples/ServerClientTemplate.zip

Entirely unobtrusive and imperative templates with Microsoft Ajax Library Preview 6

(c) 2009 Bertrand Le Roy Today is the release of the sixth preview of Microsoft Ajax Library. Don’t get fooled by the somewhat silly and long name: this is a major release in many ways. The scripts have been majorly refactored since preview 5. Check out the other posts out there (links at the bottom of this post) to see just some of the many new features that are in there. Some of my favorite are all the small improvements that have been made to make imperative instantiation of components and templated contents easier than ever. Many of you have told us that you preferred to do things imperatively and this release makes it a lot better.

When Preview 5 came out, I built a simple class browser using the declarative syntax. The class browser shows the hierarchy of namespaces and classes in a tree view on the left side of the page, and the details of whatever’s selected in the tree on the right side of the page:The JavaScript class browserhttp://weblogs.asp.net/bleroy/archive/2009/09/14/building-a-class-browser-with-microsoft-ajax-4-0-preview-5.aspx

It still works (and an updated version is attached to this post), but I thought I would demonstrate how you can take that same sample and re-implement it in a completely imperative way. Of course, you never have to go all the way one way or another, and it’s always possible for example to use the nice declarative syntax for bindings but instantiate your components imperatively if you choose to do so. In this post, I’m deliberately going imperative all the way. Just keep in mind this is rather extreme.

The first thing to notice in the new version is that the markup is perfectly clean and contains no weird extension, namespace or custom binding syntax whatsoever. It’s 100% pure HTML 5. Here is for example the complete markup for the tree view on that page:

<ul id="tree" class="tree"></ul>

<ul id="nodeTemplate" class="sys-template">
    <li>
        <a class="toggleButton" href="#">+</a>
        <a class="treeNode" href="#"></a>
        <ul></ul>
    </li>
</ul>

The script that builds the dynamic contents is bootstrapped by the following code:

<script type="text/javascript"
src="Scripts/start.js"></script> <script type="text/javascript"> Sys.loadScripts(["Scripts/Tree.js"], function() { Sys.require([Sys.components.dataView], function() { createTreeView("#tree",
Type.getRootNamespaces(),
"#nodeTemplate"); Sys.create.dataView("#detailsChild", { itemRendered: onDetailsChildRendered }); }); }); </script>

We’re making use of the new script loader here: we first include the bootstrapper file, start.js, and then we declare that we need one custom script, “tree.js” and everything necessary to instantiate a DataView. The script loader will figure out on its own the set of scripts it needs to download for that. Once those scripts have been downloaded, we call createTreeView, which is custom code that we’ll look at in a moment that creates nested DataView controls over the markup. We also create a second DataView to display the details of what’s selected in the  tree.

Notice that we set some properties to a selector string here (for example “#nodeTemplate”). This is actually a breaking change from the previous preview, which only understood id strings. Microsoft Ajax does not include a full selector engine but it does understand the most basic of selectors (.class, tagName and #id). But where it gets really interesting is that if you had included jQuery on the page, the framework would detect it and enable you to use full selectors everywhere. Isn’t that sweet?

So how does the imperative approach compare with the declarative one? Well, for instantiating components, you already have an example above, where we use Sys.create.dataView. But what about wiring up events, setting text contents and attribute values, instantiating components over the markup inside the template?

All those are done by post-processing the template instances after they’ve been instantiated, by handling the itemRendered event:

itemRendered: function(sender, args) {
  // do magic
}

Wiring up events is as simple as getting a reference to an element and calling addHandler:

var toggleButton = args.get(".toggleButton");
Sys.UI.DomEvent.addHandler(toggleButton, "click",
function(e) { toggleVisibility(this); }, true);

The args.get function, which you will use a lot, takes a selector and returns the first element that matches it inside the template. Here, we are looking for an element with class “toggleButton”, but a local id would work just as well.

To set text contents and attribute values is trivial once you know how to get references to elements from local selectors (remember, jQuery also works here transparently or even explicitly when and if you need it).

Finally, instantiating components is also quite easy. For example, here is the code that creates an inner DataView for the child nodes of a node in the tree, recursively:

var childView = args.get("ul");
createTreeView(childView,
getChildren(args.dataItem),
nodeTemplate);

The args.get funtion is used once more to get a reference to the first UL element within the template, and it is then easy to do a recursive call into our tree creation function and build the new branch of the tree.

The command bubbling feature that makes it so easy to wire up custom commands into a template is still usable in imperative code:

var treeNode = args.get(".treeNode");
Sys.setCommand(treeNode, "select");

Finally, there is one feature that I’m not using in that sample, but that’s immensely useful, and I’m talking of course of live bindings. Those work too, all you have to do is call the Sys.bind function and give it the target object, the name of the target property to bind, the source object and the source property name.

To render the details view, I decided to not use a single item DataView like I did with the declarative version: since I’m going to use imperative code instead of declarative bindings, it is just as easy to directly manipulate the DOM that already exists, and do some hiding and showing of elements:

function onCommand(sender, args) {
  if (args.get_commandName() === "select") {
    var dataItem = sender.findContext(
args.get_commandSource()).dataItem; var isClass = Type.isClass(dataItem) &&
!Type.isNamespace(dataItem); var childData =
(isClass ? getMembers : getChildren)(dataItem), namespaceElementsDisplay =
isClass ? "none" : "block", classElementsDisplay =
isClass ? "block" : "none", detailsChild =
Sys.Application.findComponent("detailsChild"); detailsChild.onItemRendering =
isClass ?
onClassMemberRendering :
onNamespaceChildRendering; detailsChild.set_data(childData); Sys.get("#detailsTitle").innerHTML =
dataItem.getName(); Sys.get("#namespacesColumn").style.display = Sys.get("#classesColumn").style.display =
namespaceElementsDisplay; Sys.get("#propertiesColumn").style.display = Sys.get("#eventsColumn").style.display = Sys.get("#methodsColumn").style.display = Sys.get("#staticMethodsColumn").style.display =
classElementsDisplay; Sys.get("#details").style.display = "block"; } }

We do have a DataView to render the contents of the currently selected object though. The nice trick we used with the declarative version to dynamically switch the target place holder where the template gets rendered is still there, which enables a single DataView control to dispatch the data into two to four separate lists (or however much you want for that matter):

function onNamespaceChildRendering(args) {
    args.set_itemPlaceholder(
        Type.isClass(args.get_dataItem()) ?
            "#classPlaceHolder" :
            "#namespacePlaceHolder"
    );
}

I think all this is pretty cool and I hope the comparison between the declarative version and the imperative version of this little application gives you a sense of the flexibility that the Microsoft Ajax library now offers, and of how much you can choose your own development style and do pretty much anything with the same ease.

Download the code for this post here:
http://weblogs.asp.net/blogs/bleroy/Samples/Preview6ClassBrowser.zip

Microsoft Ajax Library Preview 6 can be downloaded from here:
http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=34488

Here are a few links about this release:
http://weblogs.asp.net/scottgu/archive/2009/10/15/announcing-microsoft-ajax-library-preview-6-and-the-microsoft-ajax-minifier.aspx
http://channel9.msdn.com/posts/jsenior/Announcing-Microsoft-Ajax-Library-Preview-6/
http://www.jamessenior.com/post/How-the-Script-Loader-in-the-Microsoft-Ajax-Library-will-make-your-life-wonderful.aspx

HTML now a data format

About a year ago, I asked the question on this blog whether HTML could and should be used as a data format:

http://weblogs.asp.net/bleroy/archive/2008/11/26/should-html-be-considered-as-a-data-format.aspx

After all, it actually already has semantic constructs appropriate for tabular data, for collections, for hierarchical data and for object graphs of any kind.

Well, apparently I wasn’t the only one to think that (not that I expected I was):

http://www.whatwg.org/specs/web-apps/current-work/multipage/microdata.html

More Posts