LA.NET [EN]

Oct 19

In the previous posts, we’ve migrated our code from a pure declarative approach to an imperative approach. Today we’ll improve our last example and we’ll see how we can perform some interesting operations by using the Sys.UI.TemplateContext object obtained by instantiating a template (ie, obtained when you call instantiateIn over a Sys.UI.Template instance).

Lets assume that we need to improve our HTML used for the template. For instance, we want to to put the name and address info into SPAN nodes. Looking at the previous sample, it’s obvious that we could simply add the necessary tags to the string passed to the innerHTML property:

itemRendered: function(sender, e) {
    //e represents the datacontext
    var data = e.dataItem;
    e.nodes[0].innerHTML = "<span>" + data.name + 
"</span>-<span>" + data.address + "</span>"; }

This would solve the problem! However, I’m disallowing this approach for this post because it wouldn’t allow us to explore the cool things we can do with the Sys.UI.TemplateContext object! Instead, lets assume that we must use the following HTML for the template (we’re still using an imperative approach here!):

var helper = document.createElement("ul");
helper.innerHTML = "<li><span id=''name''></span>” + 
“-<span id=''address''></span></li>"
;

Now, the question is: how do we access the span nodes from within the itemRendered events? Option number 1 relies on navigating through the created nodes. If you recall our last sample, you’ll remember that the ItemRendered event receives an instance of a Sys.UI.TemplateContext object. We can use this object to get a reference to the HTML created from the template instantiation (e.nodes returns a collection of nodes; in the previous example, there’s only one top node – the LI element). Here’s the code that shows how to set up the span’s content by using this strategy:

itemRendered: function(sender, e) {
    //e represents the datacontext
    var data = e.dataItem;
    var nameNode = e.nodes[0].childNodes[0];
    var addressNode = e.nodes[0].childNodes[2];
    nameNode.innerHTML = data.name;
    addressNode.innerHTML = data.address;
}

As you can see,we use the childNodes property for getting a reference to the correct elements we want to customize. The previous code might caught you off guard…just remember: childNodes returns a reference to all the child nodes of the LI element  (including text nodes!).

Now,if you paid attention to the initial definition of the HTML used by template, you’ve probably noticed that we gave IDs to the inner spans. I did that for a reason: to allow me to get them in a fast, non-error prone way. When you have IDs, you can use the Sys.get helper for getting a reference to the element. Take a look at the improved code:

itemRendered: function(sender, e) {
    //e represents the datacontext
    var data = e.dataItem;
    var nameNode = Sys.get("#name", e);
    var addressNode = Sys.get("#address", e);
    nameNode.innerHTML = data.name;
    addressNode.innerHTML = data.address;
}

If you’ve read the previous post on Sys.get, you’ll recall that the parameter used as a second parameter is used as the context for the search, ie, it limits the search to that context. You probably recall that the only restriction applied to the context parameter was that it should expose a get method which is responsible for doing all the work. In practice, that means that we can simplify the code by using that method directly:

itemRendered: function(sender, e) {
    //e represents the datacontext
    var data = e.dataItem;
    var nameNode = e.get("#name");
    var addressNode = e.get("#address");
    nameNode.innerHTML = data.name;
    addressNode.innerHTML = data.address;
}

You might be a little worried because you might be thinking that template instantiation is introducing duplicate IDs in your page. It might happen, but not in the template instantiation code. Let me be clear here: template instantiation code will always generate elements with different IDs (ie, if you concentrate on the HTML generated in the previous example, you’ll see that the HTML for the DataView control doesn’t have any duplicated IDs). However, it cannot guarantee no duplications at page level since that would mean lots and lots of processing (it expects that you, the developer, configure the template correctly so that the generated IDs won’t introduce any duplication at page level). Btw, template instantiation will only generate IDs for the elements that have an ID; if you don’t set the ID in the HTML elements that define the template, none will be generated.

The next image shows the resulting HTML introduced in the page:

templateInstantiation

As you can see, the final IDs is obtained by combining the ID  you’ve used in the template with the position of the row in the data source used to feed the DataView control.

Besides the get method, the Sys.UI.TemplateContext introduces other methods you might find useful:

  • getInstanceId: this method expects a string with the base ID and generates a new ID based in the position of the template instantiation in the container. This method is used internally for getting the ID that is applied for each generated element;
  • query: lets you pass an expression and returns the element(s) that match it. Internally, this ends up calling the same method that is used by the public Sys.get helper (the main difference is that it can return several nodes, instead of returning a single one).

Before ending, you should know that the DataView saves all the Sys.UI.TemplateContext instances used during template instantiation. You can access this collection because the DataView control exposes the read-only contexts property (get_contexts). In practice, this means that you can, at any moment, access the data that has been used to generate any of the lines generated by the DataView control . Pretty cool, right?

And that’s it for now. Stay tuned for more on MS AJAX.

1 comment so far

  1. hooperma
    4:02 pm - 1-5-2010

    Should Sys.UI.TemplateContext.getInstanceId() be using context._tcindex rather than context.index to generate id strings? The index property is causing duplicate ids but using _tcindex seems to fix the problem.