W8WIL #2: Declaratively Specifying an ItemTemplate in a Fragment

I’ve been playing quite a bit over the last few days with the new Windows 8 Release Preview, as part of a special team project I’m working on with some of my fellow DEs. One of the areas I was working on is doing some simple databinding using a ListView control in a JavaScript Metro style app based on the Navigation App template. In this second installment of my Windows 8, What I’ve Learned series, I’ll give you a tip that may help save you some pain and troubleshooting time when declaratively associating an ItemTemplate for a ListView control inside a page fragment.

I was able to very easily create an array with a couple of objects, each with a couple of properties, and then bind those to the ListView by passing the array to the constructor of the WinJS.Binding.List object, which gave me a List object with a dataSource property that I could assign to the ListView’s itemDataSource property in the ready() function of home.js, like so:

listView.winControl.itemDataSource = myList.dataSource;

So far, so good…when I ran the project, the data showed up, in JavaScript object style, as expected. But since that’s not a very interesting way to display data, I of course needed to add an ItemTemplate, similar to the following:

   1:  <div id="myTemplate" data-win-control="WinJS.Binding.Template">
   2:     <div>
   3:        <div class="win-type-large myTitle" data-win-bind="textContent: title">
   4:     </div>
   5:  </div>

Once I had my template declared (note the data-win-control attribute that tells WinJS to instantiate this as a BindingTemplate), I had to tell my ListView about it, which I could do either programmatically or declaratively.

TIP: If you look at either the Grid App or Split App JavaScript templates, both show examples of assigning a template to a ListView programmatically.

I find declarative syntax a bit simpler, so I wanted to do it that way. In previous demos I’ve done, the syntax looked like this:

<div id="listView" data-win-control="WinJS.UI.ListView" 
   data-win-options="{itemTemplate : myTemplate}"></div>

I dutifully added the data-win-options attribute to my ListView markup, ran the project again, and…nothing. The underlying data was still being rendered as a JavaScript object.

I spent a couple of hours pulling my hair and making little changes to the code before it finally dawned on me to check the ListView quickstart documentation, and lo and behold, it turns out that the declarative syntax above doesn’t work when your markup is part of a page fragment, which is what you get as part of the Navigation App template. Instead, you need to use the following syntax:

<div id="listView" data-win-control="WinJS.UI.ListView" 
   data-win-options="{itemTemplate : select('#myTemplate')}"></div>

The “select” will walk the DOM to resolve the reference, while the direct id reference in the first example won’t work because the fragment markup hasn’t been added to the DOM by the time that the resolution takes place.

So if you’re working with ItemTemplates declaratively in page fragments, be sure to use the “select(‘#templateId’)” syntax to associate your template with your ListView.

(h/t Jeff Sanders – moderator in the Metro Style apps forums for more detail on the underlying issue)