2012

Volume 27

JavaScript - Data Binding in a Windows Store App with JavaScript

By Chris Sells | 2012

In this article we’ll explore data binding in a Windows Store app built with JavaScript. This is a hybrid of other kinds of apps built for Windows 8. It’s like a desktop app in that it’s installed on your computer, unlike a Web site. On the other hand, it’s like a Web site in that you can build it using HTML5, JavaScript and CSS3. However, instead of generating the UI on the server side, the JavaScript framework for building Windows Store apps and the underlying Windows Runtime allows you to build apps with client-side state, offline storage, controls, templates and binding—along with a whole host of other services.

Data binding is the ability to take the value of a list of data, such as a set of RSS feeds, and use it to populate a control, such as a ListView. We can tailor which data we extract using templates. We’ll show how binding is even more flexible than that, allowing updating of the UI as the underlying data changes, along with sorting, filtering and grouping.

When we use data binding, it’s often in the context of a control. We’re going to take a look at the ListView and its support for data binding and templates.

Data Binding 101

The use of binding allows you to set up an association between two properties on two objects, most often associating the property of an object with a property on an HTML Document Object Model (DOM) element, as Figure 1 shows.

Binding Between an Attribute on a Destination Element and a Property from a Source Object

Figure 1 Binding Between an Attribute on a Destination Element and a Property from a Source Object

The purpose of establishing a binding is to copy data between the two objects involved: the source from where the data comes and the destination to which the data goes. You might think that you can accomplish this goal using a simple assignment statement:

myDestElem.value = mySourceObj.name;

Fundamentally, assignment is what binding does. However, binding is not just a description of what data to copy and to where, but also when. The “when” of a binding is generally one of the following:

  • One-way binding: Copy the data to the DOM element when the object changes. This is the default in the Windows Library for JavaScript (WinJS).
  • One-time binding: Copy the data to the DOM element when the binding is first established. This is the equivalent of assignment.
  • Two-way binding: Copy the data to the DOM element when the object changes and copy the data to the object when the DOM element changes. This isn’t supported in WinJS.

By default, WinJS binding is one-way binding, although one-time binding is supported as well. Although WinJS doesn’t support two-way binding, there’s a nice place to hook in your favorite two-way binding engine, such as the one in jQuery, as you’ll see.

Binding Objects

To get started, let’s say we want to build a little browser for the people in our lives, as shown in Figure 2.

Figure 2 Binding an Object to a Set of HTML Elements

The idea is that we can have a number of people through whom we can navigate, each with a name, age and a favorite color. As we use the previous and next buttons, we navigate to other people in the list, and if we press the button in the middle—the clock—we celebrate a birthday by increasing the age of the currently shown person. The following represents the set of people we’ll be browsing in our sample:

var people = [
  { name: "John", age: 18, favoriteColor: "red" },
  { name: "Tom", age: 16, favoriteColor: "green" },
  { name: "Chris", age: 42, favoriteColor: "blue" },
];

Starting from a Navigation Application project template in Visual Studio 2012 provides HTML for us to populate, as shown in Figure 3.

Figure 3 The Main Form

<!DOCTYPE html>
<!-- homePage.html -->
<html>
<head>
  <meta charset="utf-8" />
  <title>homePage</title>
  <!-- WinJS references -->
  <link href="//Microsoft.WinJS.1.0/css/ui-light.css" rel="stylesheet" />
  <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
  <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
  <link href="/css/default.css" rel="stylesheet" />
  <link href="/pages/home/home.css" rel="stylesheet" />
  <script src="/pages/home/home.js"></script>
</head>
<body>
  <!-- The content that will be loaded and displayed. -->
  <div class="fragment homepage">
    <header aria-label="Header content" role="banner">
      <button class="win-backbutton" aria-label="Back"
        disabled type="button"></button>
      <h1 class="titlearea win-type-ellipsis">
        <span class="pagetitle">Welcome to PeopleBrowser!</span>
      </h1>
    </header>
    <section aria-label="Main content" role="main">
      <!-- display each person -->
      <div id="nameLabel">Name</div>
      <input id="name" readonly="true" type="text" 
        data-win-bind="value: name" />
      <div id="ageLabel">Age</div>
      <input id="age" readonly="true" type="text" 
        data-win-bind="value: age" />
      <div id="colorLabel">Favorite Color</div>
      <div id="color" data-win-bind="style.backgroundColor:
        favoriteColor"></div>
      <div id="buttons">
        <button id="previousButton"></button>
        <button id="birthdayButton"></button>
        <button id="nextButton"></button>
      </div>
    </section>
  </div>
</body>
</html>

The interesting part of this HTML is the use of the data-win-bind attribute, which uses the following format:

<div data-win-bind="destProp1: sourceProp1; destProp2: sourceProp2;..."></div>

The data-win-bind syntax is a semicolon-delimited list of binding expressions. Each expression is the combination of a destination DOM element property and a source object property. The dotted syntax we’re using to set the background color on the style for the favorite color div—that is, style.backgroundColor—works for properties on both the source and the destination, and it drills into subobjects, as you’d expect.

Each destination property in a binding expression is resolved against the HTML element that contains the data-win-bind attribute. The question is: Where does the object come from against which the property names are resolved? And the answer is: the data context.

Setting the data context is part of the binding operation, which establishes the association between the HTML element and whatever object is used as the data context, as shown in Figure 4.

Figure 4 Setting the Data Context

// homePage.js
(function () {
  "use strict";
  WinJS.UI.Pages.define("/pages/home/home.html", {
    ready: function (element, options) {
      var people = [
        { name: "John", age: 18, favoriteColor: "red" },
        { name: "Tom", age: 16, favoriteColor: "green" },
        { name: "Chris", age: 42, favoriteColor: "blue" },
      ];
      // Bind the current person to the HTML elements in the section
      var section = element.querySelector("section[role=main]");
      var current = 0;
      WinJS.Binding.processAll(section, people[current]);
    }
  });
})();

The processAll function in the WinJS.Binding namespace is the function that parses the data-win-bind attributes for a given hierarchy of HTML elements, the section containing the input and div elements in our sample. The call to processAll establishes the bindings between the HTML elements and the data context as described in each data-win-bind attribute. The data context is the second argument to processAll and is used to resolve the property names found in each binding expression. The results already look like what we’re after, as shown in Figure 2.

By default, if we do nothing else, we’ve established a one-way binding connection between the data context object and the DOM element. That means that as properties on the data source object change, we expect the output to change as well, as shown in Figure 5.

Figure 5 As Properties on the Data Source Change, So Does the Output

function ready(element, options) {
  var people = [
    { name: "John", age: 18, favoriteColor: "red" },
    { name: "Tom", age: 16, favoriteColor: "green" },
    { name: "Chris", age: 42, favoriteColor: "blue" },
  ];
  var section = element.querySelector("section[role=main]");
  var current = 0;
  WinJS.Binding.processAll(section, people[current]);
  birthdayButton.onclick = function () {
    var person = people[current];
    person.age++; // Changing a bound property doesn't work yet ...
  };
}

Our implementation of the click handler for the birthday button looks up the current element and changes a property, specifically the age. However, we’re not quite where we need to be to get the UI to update automatically.

The problem is that a standard JavaScript object doesn’t support any notification protocol to inform interested parties—such as a binding—that its data has changed. To add the notification protocol is a matter of calling the as method from the WinJS.Binding namespace, as shown in Figure 6.

Figure 6 Adding the Notification Protocol

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    var current = 0;
    WinJS.Binding.processAll(section, people[current]);
    birthdayButton.onclick = function () {
      var person = people[current];
      person.age++; // Now this works!
    };
  }
});

The “as” method wraps each object, providing the binding notification protocol so each property change notifies any binding listeners (such as our bound HTML elements). With this code in place, changing a person’s age is reflected in the UI, as Figure 7 shows.

Changing the Underlying Data Automatically Updates the Bound HTML Elements
Figure 7 Changing the Underlying Data Automatically Updates the Bound HTML Elements

We’ve been binding a single person object to the set of HTML elements for display, but you can process the data-binding expressions in the data-win-bind attributes with a different kind of data context, as shown in Figure 8.

Figure 8 Processing the Data-Binding Expressions

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    var current = 0;
    var viewModel = WinJS.Binding.as({ person: people[current] });
    WinJS.Binding.processAll(section, viewModel);
    birthdayButton.onclick = function () {
      viewModel.person.age++;
    };
    // Bind to the previous object
    previousButton.onclick = function () {
      current = (people.length + current - 1) % people.length;
      viewModel.person = people[current];
    };
    // Bind to the next object
    nextButton.onclick = function () {
      current = (people.length + current + 1) % people.length;
      viewModel.person = people[current];
    };
  }
});

Here’s where we make a shift between passing in a single piece of data from our app’s “model” (that is, the set of data that has nothing to do with the display of itself) to grouping the data that’s appropriate for our “view” of that model (in this case, the current person to view). We call this variable the “view model” after a famous and useful technique for implementing UIs called Model-View-ViewModel (MVVM). Once we’ve built our view model as a bindable object, as the underlying properties change (the person, in our case) the view is updated. We then bind our view to the view model so that in our Next and Back button handlers—as we change which person we’d like to view—the view is notified. For this to work, we’ll need to update the HTML to use the view model instead of the person directly, as shown in Figure 9.

Figure 9 Updating HTML to Use the View Model

<section aria-label="Main content" role="main">
  <!-- display each person -->
  <div id="nameLabel">Name</div>
  <input id="name" readonly="true" type="text" 
    data-win-bind="value: person.name" />
  <div id="ageLabel">Age</div>
  <input id="age" readonly="true" type="text" 
    data-win-bind="value: person.age" />
  <div id="colorLabel">Favorite Color</div>
  <div id="color" 
    data-win-bind="style.backgroundColor: person.favoriteColor"></div>
  <div id="buttons">
    <button id="previousButton"></button>
    <button id="birthdayButton"></button>
    <button id="nextButton"></button>
  </div>
</section>

Figure 10shows the result.

You Can Rebind Different Objects to the Same Set of HTML Elements
Figure 10 You Can Rebind Different Objects to the Same Set of HTML Elements

In addition to binding objects to elements, binding also allows you to simply listen for a value to change. For example, right now as we change the index to the current value when the user clicks the previous or next buttons, we have to remember to write the code to change the view model’s person field to match. However, you could use binding itself to help here, as shown in Figure 11.

Figure 11 Reprocessing Binding Expressions

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    // Listen for the current index to change and update the HTML
    var viewModel = WinJS.Binding.as({ current: 0, person: null });
    WinJS.Binding.processAll(section, viewModel);
    viewModel.bind("current", function (newValue, oldValue) {
      viewModel.person = people[newValue];
    });
    birthdayButton.onclick = function () {
      viewModel.person.age++;
    };
    // Bind to the previous object
    previousButton.onclick = function () {
      // Set the current index and let the binding do the work
      viewModel.current = (people.length + 
        viewModel.current - 1) % people.length;
    };
    // Bind to the next object
    nextButton.onclick = function () {
      // Set the current index and let the binding do the work
      viewModel.current = (people.length + 
        viewModel.current + 1) % people.length;
    };
  }
});

Instead of a simple variable to hold the index to the currently shown person, we add the index to the currently viewed person to our bindable view model. All bindable objects have a bind method, which allows us to listen for changes to the object’s properties (the current property in this example). When the user clicks on the previous or next buttons, we simply change the index of the current person to be shown and let the bind handler process the data-win-bind attributes for the HTML that shows the current person.

If you want to stop listening for bind events, you can call the unbind method.

Now, as we mentioned, everything you’ve seen works against the default: one-way binding. However, if you’d like to set up other kinds of binding or participate in the binding process itself, you can do so with a binding initializer.

Initializers

An initializer is the optional third parameter to a binding expression that specifies a function to call when the binding is established:

<div data-win-bind="destProp: sourceProp init" ...></div>

You provide an initializer as part of a binding expression if you want to participate in or even replace the existing binding behavior—for example, to perform a data conversion or even hook up jQuery two-way binding. A binding initializer is a function that takes over for the default one-way binding and has the following signature:

function myInit(source, sourceProperties,
  dest, destProperties) {...}

The details of implementing a custom initializer are beyond the scope of this article, but WinJS has several initializers built-in of which you can take advantage. For example, if you’d like to do one-time instead of one-way binding, you can use the oneTime function from the WinJS.Binding namespace:

<input data-win-bind=
  "value: person.name WinJS.Binding.oneTime"></input>

On the other end of the spectrum, when performing one-way binding, it’s often useful to perform data conversion (also known as data transformation). For example, imagine we wanted to spell out the ages of the people in our life:

function getWordsFromNumber(i) {...}
// Convert ages to words
window.ageToWords =
  WinJS.Binding.converter(function (value) { 
    return getWordsFromNumber(value); 
  });

The converter function on the WinJS.Binding namespace provides the hard part of the initializer implementation; all you have to do is provide a function to perform the actual conversion and it will be called as the source value changes. Using it in the HTML looks like you’d expect:

<input data-win-bind="value: person.age ageToWords"></input>

You can see the results in Figure12.

Translating a Numeric Age into Words via Data Conversion
Figure 12 Translating a Numeric Age into Words via Data Conversion

Binding values one at a time is useful, but even more useful—especially for Windows Store apps—is binding collections of values all at once. For that we have the binding list.

A Binding List

Imagine a simple example of using a ListView with a collection of values:

<div data-win-control="WinJS.UI.ListView"
  data-win-options="{itemDataSource: items.dataSource}">
</div>

Here we’re creating a ListView control declaratively in HTML that’s bound to the dataSource property of a global items object. In our JavaScript, it’s easy to create and populate the items object as a binding list:

// A global binding list of items
window.items = new WinJS.Binding.List();
[0, 1, 2].forEach(function (i) {
  WinJS.Promise.timeout(500 * (i+1)).done(function () {
    // Add an item to the binding list, updating the ListView
    items.push(i);
  });
});

In this code we create a binding list (an instance of the List type from the WinJS.Binding namespace) and we loop over an array of values, using each to create a timeout, which is a promise that will fire at some time in the future according to the argument you pass (milliseconds). When each timeout completes, we’ll see the ListView get an additional value, as Figure 13 shows.

The ListView Updating as the Underlying Binding List Updates
Figure 13 The ListView Updating as the Underlying Binding List Updates

The HTML doesn’t provide an ID for the ListView, nor does the JavaScript interact with the ListView in any way. Instead, the HTML and the JavaScript both rendezvous on the items binding list. It’s the binding list that implements the collection binding API (called IListDataSource). Instead of making you program against IListDataSource directly—it’s not particularly programmer-friendly—the binding list exposes its IListDataSource implementation via the dataSource property.

To provide an API that’s as familiar as possible to JavaScript programmers, the binding list implements a similar API and similar semantics as the built-in array supports—for example, push, pop, slice, splice and so on. As a comparison, here’s how the built-in JavaScript array works:

// Using the built-in array
var array = [];
array.push("one");
array.push("two");
array.push("three");
var x = array[0]; // x = "one"
var y = array[1]; // y = "two"
array[2] = "THREE";
var z = array[2]; // z = "THREE";

The binding list behaves similarly except that instead of using an indexer—that is, square brackets—it exposes items via setAt and getAt:

// Using the WinJS binding list
var list = new WinJS.Binding.List();
list.push("one");
list.push("two");
list.push("three");
var x = list.getAt(0); // x = "one"
var y = list.getAt(1); // y = "two"
list.setAt(2, "THREE");
var z = list.getAt(2); // z = "THREE";

Sorting and Filtering

In addition to the familiar API, the binding list was built with Windows Store app building needs in mind. You’ve already seen how the dataSource property lets you connect to the ListView control. In addition, you might be interested in sorting and filtering your data. For example, here’s our list of people again, this time wrapped in a binding list:

var people = new WinJS.Binding.List([
  { name: "Tom", age: 16 },
  { name: "John", age: 17 },
  { name: "Chris", age: 42 },
]);
// Sort by name
window.sortedPeople = people.
  createSorted(function (lhs, rhs) { 
    return lhs.name.localeCompare(rhs.name); 
  });
// Filter by age (adults only)
window.filteredPeople = people.
  createFiltered(function (p) { return p.age > 17; });

We can sort a binding list by calling the createSorted method, passing in a sorting function, or filter it by calling the createFiltered method, passing in a function for filtering. The result of calling one of these create methods is a view over the data that looks and acts like another instance of the binding list, and we can bind it to a ListView, as Figure 14 shows.

Filtering a Binding List
Figure 14 Filtering a Binding List

Instead of providing a copy of the underlying data, the createSorted and createFiltered methods return a live view over the existing data. That means that any changes to the underlying data are reflected in the views and will be shown in any bound controls. For example, we could add a minor to the underlying list:

// Changes to the underlying data are reflected in the live views
var person = { name: "Pete", age: 17, favoriteColor: "black" };
people.push(person);

Even though we’re changing the underlying data, the sorted view will be updated and the ListView will be notified of the change, as Figure 15 shows.

Sorting a Binding List
Figure 15 Sorting a Binding List

Also, because the view from the create methods looks and feels like a binding list, you can further sort or filter the view in a stacked way:

// Filterd by age (minors) and sorted by name
window.filteredSortedPeople = people.
  createFiltered(function (p) { return p.age < 18; }).
  createSorted(function (lhs, rhs) { 
    return lhs.name.localeCompare(rhs.name); 
  });

The results of binding to the resultant filtered and sorted view shouldn’t be a surprise (see Figure 16).

Sorting and Filtering a Binding List
Figure 16 Sorting and Filtering a Binding List

Be careful when stacking that you do so in the correct order. In the case of filtering, if you sort or group first and then filter, you’re doing more work than you have to. Also, every view layer is overhead, so you’ll want to make sure you stack them only as deep as necessary.

Grouping

In addition to sorting and filtering over the binding list data, you can also group it by some criteria of the data. For example, adults and minors would work well for our sample data:

// Group by age
window.groupedPeople = people.
  createGrouped(function (p) { return p.age < 18 ? "minor" : "adult" });

The return value of the grouping function is a string value that uniquely identifies the group—in our case, either the string “minor” or the string “adult.” Binding to the grouped view of the data shows the data arranged by group—that is, all items from each group before moving onto the next group, as Figure 17shows.

Grouping a Binding List
Figure 17 Grouping a Binding List

This example shows just two groups, but you can have any number of groups. Also, just like createSorted and createFiltered, the createGrouped method returns a view over live data, so changes in the underlying data will be reflected in bind destinations.

However, while it’s clear to us, the developers, that we’re sorting the groups—first the adults and then the minors—it’s not clear to users of our program because there’s no visual indicator of the grouping. To ask the ListView to provide a visual grouping indicator, the ListView allows you to specify two sets of data: the list of grouped items and the groups themselves. Configuring the ListView with both sets of data looks like this:

<div data-win-control="WinJS.UI.ListView"
  data-win-options="{itemDataSource: groupedPeople.dataSource,
                     groupDataSource: groupedPeople.groups.dataSource}">
</div>

Once we’ve created the grouped view of the binding list, the groups property exposes a list of those groups so the ListView can use them. However, before we can make it work, we also need to go back to our use of the createGrouped function:

// Group by age
function groupKeySelector(p) { return p.age < 18 ? "minor" : "adult"; };
function groupDataSelector(p) { return p.age < 18 ? "minor" : "adult"; };
window.groupedPeople = people.createGrouped(groupKeySelector, groupDataSelector);

Previously, when we were grouping, we just needed to provide a function that could do the grouping based on some unique group identifier. However, if we want to actually display the groups for the user, we need another method that can extract the groups themselves (if you wanted to choose the order of the groups, you could provide a third method to the createGroup method that does the sorting). In both cases, we’re providing a string to represent the group as well as to build the list of groups, which works just fine, as you can see in Figure 18.

Grouping a Binding List with ListView Headers
Figure 18 Grouping a Binding List with ListView Headers

As Figure 18 shows, the group is actually used to decorate the grouped data, making it very easy to see which data falls into which group. Unfortunately, even with this visual indication of grouping, our JSON-formatted objects aren’t really the UI we’d want to show our users. For this to work the way we want requires templates.

Templates

A template is a single-rooted hierarchy of HTML elements with optional “holes” to fill in dynamic data. The data-win-bind attribute on the div defines the holes using data-win-bind attributes. For example, we could create a template for our person objects like so:

<div id="itemTemplate" data-win-control="WinJS.Binding.Template">
  <span data-win-bind="style.color: favoriteColor">
    <span data-win-bind="textContent: name"></span>
    <span> is </span>
    <span data-win-bind="textContent: age"></span>
    <span> years old</span>
  </span>
</div>

What makes this chunk of HTML a template is the data-win-control attribute set to the WinJS.Binding.Template control type. Once we have our template, you need to render it to fill in the holes with data:

// Manual template rendering
var person = { name: "Pete", age: 17, favoriteColor: "black" };
var template = itemTemplate.winControl;
template.render(person).
  done(function (element) { peteDiv.appendChild(element); });

Because the template is just another control (although a control that hides itself until manually rendered), we can reach into the div that defines it and gain access to its functionality via a well-known property called winControl. The functionality we want to access is the template’s render method, which takes a data context for use in binding the data-win-bind attributes and produces a fully formed HTML element for us to do what we want with.

If you provide the ListView a template, it will render each item in the ListView with that template. In fact, the ListView can have templates for rendering both items and group headers. To see that in action, let’s first update the groups to objects, as is more typical:

// Fancy group by age
var groups = [{ key: 1, name: "Minor" }, { key: 2, name: "Adult" }];
function groupDataSelector(p) { 
  return p.age < 18 ? groups[0] : groups[1]; 
};
function groupKeySelector(p) { return groupDataSelector(p).key; };
window.fancyGroupedPeople = 
  people.createGrouped(groupKeySelector, groupDataSelector);

In this code, we’ve got two group objects, each with a key and a name, and we’ve got separate data and key selector functions that return the group itself or the group’s key, respectively. With our group data made a little more real-world-like, a template for the group header is created, as shown in Figure 19.

Figure 19 A Template for the Group Header

<div id="headerTemplate" data-win-control="WinJS.Binding.Template">
  <span data-win-bind="textContent: name"></span>
</div>
<div id="itemTemplate" data-win-control="WinJS.Binding.Template">
  <span data-win-bind="style.color: favoriteColor">
    <span data-win-bind="textContent: name"></span>
    <span> is </span>
    <span data-win-bind="textContent: age"></span>
    <span> years old</span>
  </span>
</div>
<h1>Fancy Grouped</h1>
<div data-win-control="WinJS.UI.ListView"
  data-win-options="{
    groupDataSource: fancyGroupedPeople.groups.dataSource,
    groupHeaderTemplate: select('#headerTemplate'),
    itemDataSource: fancyGroupedPeople.dataSource,
    itemTemplate: select('#itemTemplate')}">
</div>

The template for the group header is created just like an item template. The group header and item templates are passed to the ListView control via the groupHeaderTemplate and itemTemplate properties in the data-win-options attribute. Our fancier grouped data looks like Figure 20.

Grouping a Binding List with ListView Headers and Templates
Figure 20 Grouping a Binding List with ListView Headers and Templates

OK, we admit that’s not very fancy, but the combination of groups and items, including templates, shows the power of the binding list. In fact, the binding list is so useful, it’s the core of the asynchronous data model exposed from the data.js file generated by the Grid Application and Split Application project templates, as shown in Figure 21.

Figure 21 The Data.js File Generated by the Grid Application and Split Application Project

// data.js
(function () {
  "use strict";
  var list = new WinJS.Binding.List();
  var groupedItems = list.createGrouped(
      function groupKeySelector(item) { return item.group.key; },
      function groupDataSelector(item) { return item.group; }
  );
  // TODO: Replace the data with your real data.
  // You can add data from asynchronous sources whenever it becomes available.
  generateSampleData().forEach(function (item) {
    list.push(item);
  });
  WinJS.Namespace.define("Data", {
    items: groupedItems,
    groups: groupedItems.groups,
    getItemsFromGroup: getItemsFromGroup,
    ...
  });
  ...
  // This function returns a WinJS.Binding.List containing only the items
  // that belong to the provided group.
  function getItemsFromGroup(group) {
    return list.createFiltered(function (item) {
    return item.group.key === group.key; });
  }
  ...
  });
})();

You can see the creation of the empty binding list, the creation of a grouped version of that list using functions that do key and data selection over the groups, a little forEach loop that adds the items to the binding list and finally, a helper function that does filtering.

Where Are We?

We started this article by digging into binding, the ability to associate a property on an object with an attribute on an HTML element. Out of the box, WinJS supports one-way, one-time and custom binding initializers, but not two-way binding. Binding is supported on single bindable objects as well as lists of objects that implement the IListDataSource interface. The easiest place to get an implementation of the IListDataSource interface is via the binding list (WinJS.Binding.List) object, which fully supports sorting, filtering and grouping. We also saw how useful templates are when combined with binding and how useful both templates and binding are when it comes to controls that support list binding, such as the ListView.


Chris Sells is the vice president of the Developer Tools Division at Telerik. He is coauthor of “Building Windows 8 Apps with JavaScript” (Addison-Wesley Professional, 2012), from which this article was adapted. More information about Sells, and his various projects, is available at sellsbrothers.com.

Brandon Satrom is a program manager in the Kendo UI UI.

Thanks to the following technical experts for reviewing this article: Chris Anderson, Jonathan Antoine, Michael Weinhardt, Shawn Wildermuth and Josh Williams