[ NOTE: This post was written using the Visual Studio 11 beta and Windows 8 Consumer Preview…as with any pre-release software, the code and concepts are subject to change in future versions ]
One of the nice features of the new JavaScript Windows Metro style app templates in the Visual Studio 11 beta is that they provide built-in support for databinding, using sample data in a JSON array. Folks who have experience in the XAML world may not see this as a particularly big deal, since Silverlight and WPF have supported databinding for a long time.
For web applications, however, data binding is still a concept that’s evolving. While there are third-party libraries like Knockout.js that provide client-side databinding (and my fellow DE David Isbitski recently published a blog post detailing how you can use Knockout in a Metro style app, if that’s your cup of tea), but in general the web world is a little behind the curve compared to XAML-based databinding.
Back to Windows 8, both the Grid Application template and the Split Application template include markup and code that demonstrates databinding to sample data contained in a file called data.js (in the js folder off the root of the app). The data.js file contains static sample data stored as JSON arrays, along with some helper functions that expose (via WinJS.Namespace.define) the collections of items, groups, and items from a specified group. This data is used by the binding templates in the HTML markup included in the application templates, such as itemsPage.html in the Split Application template.
As with most generated JavaScript files in the Metro style app templates, data.js uses a self-executing anonymous function to wrap the code that defines the sample data. This both ensures that the code that creates the JSON data (and related helper code) executes as soon as data.js is loaded, and also hides the internal variables declared in data.js so that they do not pollute the global JavaScript namespace.
Both application templates use the same sample data, which has the following schema:
sampleGroups
– key
– title
– subtitle
– backgroundImage (maps to one of 3 variables containing a base64 encoded png image)
sampleItems
– group (maps to sampleGroups above)
– title
– subtitle
– description (maps in the sample data to the itemDescription variable)
– content (maps in the sample data to the itemContent variable)
– backgroundImage (maps to one of 3 variables containing a base64 encoded png image)
In addition to declaring sampleGroups and sampleItems as JSON arrays, data.js creates a WinJS.Binding.List called list, and then calls its createGrouped method (passing in the parameters for grouping, which in this case are functions that return the group key and group), and finally loops through the sampleItems array using forEach, and adds each item to the binding list object.
Once the binding list(s) are available, they are typically bound to the HTML markup either declaratively with attributes or programmatically in JavaScript. For example, in the itemsPage.html file of a Split application, the default UI for displaying the groups is a ListView control, which is implemented as a div element with the data-win-control attribute set to WinJS.UI.ListView:
<div class="itemslist" aria-label="List of groups" data-win-control="WinJS.UI.ListView" data-win-options="{ selectionMode: 'none' }"> </div>
(note that in order for the data-win-control attribute to convert the div element into a ListView control, the app must call WinJS.UI.processAll(), which is done by default in default.js in the Grid and Split application templates)
In the case of the Split application template, the JavaScript file for itemsPage.html, which is named itemsPage.js contains the following code in the ready handler which sets the datasource of the ListView to the groups defined in the sample data:
1: var listView = element.querySelector(".itemslist").winControl;
2: ui.setOptions(listView, {
3: itemDataSource: data.groups.dataSource,
4: itemTemplate: element.querySelector(".itemtemplate"),
5: oniteminvoked: this.itemInvoked.bind(this),
6: });
(in the code above, ui is an alias to WinJS.UI)
The code above gets a reference to the ListView control by querying for the class name associated with the control, and then passes that object into the call to WinJS.UI.setOptions, setting the itemDataSource to data.groups.dataSource (which is the dataSource property on the WinJS.Binding.List object), and the itemTemplate to the item template defined in the markup (again, obtained by querying for the matching class name).
Here’s what the item template looks like:
<!-- This template is used to display each item in the ListView declared below. --> <div class="itemtemplate" data-win-control="WinJS.Binding.Template"> <img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" /> <div class="item-overlay"> <h4 class="item-title" data-win-bind="textContent: title"></h4> <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6> </div> </div>
Notice again the use of the HTML5 data- attributes, in this case both data-win-control to define the outside div element as a WinJS.Binding.Template, and the data-win-bind attributes to define the relationship between attributes of the individual elements (for example, the src attribute of the img element) and the values to which they’re being bound (in the case of the img element, the src attribute is bound to the backgroundImage property, and the alt attribute is bound to the title property).
Once the code in the ready handler has executed, the call to WinJS.UI.processAll() from default.js will complete the binding process, and you should see something like the following:
Databinding in JavaScript Windows Metro style apps is easy and straightforward, and having a template that provides a clear implementation with sample data can help you get started with your own application. This post just scratches the surface, but I wanted to walk through the basics of the databinding implementation before delving deeper into topics like customization and binding converters, which I’ll cover in future posts.
If you just can’t wait, here’s a list of additional resources that will help you dig deeper into databinding in JavaScript Metro style apps:
- Data Model for JavaScript Metro style app templates
- Details on the JavaScript project templates for Metro style apps
- Details on the JavaScript item templates for Metro style apps (Search Contract, Share Contract, etc.)
- Details on the JavaScript project templates for Metro style apps
Comments
Comment by Webguy on 2012-05-01 15:43:00 +0000
Keep up the good work my friend 🙂
Comment by devhammer on 2012-05-02 07:22:00 +0000
Will do, and thank you for the kind words of encouragement.
Comment by MZO on 2012-05-13 03:08:00 +0000
The data in listview is static. You put it and it remains as it is. How to make it dynamic?is there any way to add data to listview when app is running?I mean if there is a listview of your contacts ie, name, address and cell no. can a user add a new contact by filling a simple form like
name:
address:
cell:
and then presses Add to list button.
is it possible?
Comment by devhammer on 2012-05-13 22:58:00 +0000
Very good questions…ones that I will definitely make a point of addressing in future posts in this series.
Comment by Nick on 2012-05-14 15:17:00 +0000
Yes, this is good, however it would be great to see dynamic databinding.
Comment by Paul Marangoni on 2012-05-14 15:48:00 +0000
Databinding was easy as pie in Internet Explorer 4 with XML data islands bound to html tables. You were able to treat the data as if it was a regular recordset with methods like movenext etc.
Comment by devhammer on 2012-05-14 16:44:00 +0000
Glad you like it, and stay tuned…more databinding posts are on the way…