December 2013

Volume 28 Number 12

Modern Apps - Everything You Need to Know About the WinJS ListView Control

By Rachel Appel | December 2013

Rachel AppelYou have data. Lots of data. You need to present this data in such a way that users can effortlessly access and make sense of it while in your app. Apps expose their data in the form of news articles, recipes, sports scores, financial charts and more, all parading in various-sized compartments across the screen and trying to attract the attention of the consumer. The vast majority of apps on the market today present data in a grid or list format because it makes sense, as small to midsize grids with data are easy for humans to consume, search and filter. From enterprise apps to personal apps to whatever the app may be, grids are the scaffolding that props up data for quick visual skimming.

In Windows Store apps, you can set up this structure for data presentation by using the ListView control. If you’re new to Windows Store app development, you can get up to speed by reading my February 2013 article, “Create Windows Store Apps with HTML5 and JavaScript” (msdn.microsoft.com/magazine/jj891058) and my July 2013 article, “Mastering Controls and Settings in Windows Store Apps Built with JavaScript” (msdn.microsoft.com/magazine/dn296546).

ListView Control Basics

Available in both HTML and XAML, the ListView is the control du jour for presenting data in a grid or list format. In Windows Library for JavaScript (WinJS) apps (the focus of this article), you can use the ListView control by setting the data-win-control attribute on a host <div> element to “WinJS.UI.ListView,” like so:

<div id="listView" data-win-control= "WinJS.UI.ListView"></div>

The <div> that hosts the ListView contains no child elements. However, it does contain basic configuration information in an attribute named data-win-options. Data-win-options lets you set any property of the ListView control using a declarative syntax in the HTML page. To use the ListView properly, you’ll need to apply the following characteristics to it:

  • The group and item templates for the ListView.
  • The group and item data sources of the ListView.
  • Whether the ListView uses a grid or list layout (the default is grid).

You should also specify whether the ListView’s item selection mode is single or multiple (the default is multiple). A basic ListView with the layout and selectionMode properties set in the data-win-options attribute looks like this:

<div id="listView" data-win-control= "WinJS.UI.ListView" data-win-options=
  "{ selectionMode: 'single', layout : {type: WinJS.UI.GridLayout} }" ></div>

Though the preceding code defines a ListView, the ListView doesn’t work all by itself. It needs the help of the WinJS.Binding.List object. The List object binds arrays filled with objects to the HTML elements defined in the item and group templates. This means that the List object defines the data to display while the template defines how to display it.

Create ListView Templates

Once you have the <div> for the ListView set up, you can move on to creating the templates for it. The ListView depends on HTML templates to display data that’s readable to the user. Luckily, the Grid, Split and Hub (the Hub is available in Windows 8.1) Windows Store app templates contain everything you need to present data in a grid or list format, including sample data, predefined ListView controls and predefined CSS classes. You can modify these templates or go ahead and create your own if you’d like. Note, however, that if you create your own templates, you should adhere to the principles of modern UI design and implement the Windows 8 silhouette as described in the Dev Center for Windows Store apps at bit.ly/IkosnL. This is done for you when you use the built-in Visual Studio templates.

The ListView requires an item template, and if you’re grouping data, then it needs a header template as well. The parent elements of the item and group templates are simple <div> elements with the data-win-control attribute set to “WinJS.Binding.Template.”

The header template should contain links for each group that, when clicked, take the user to a page that lists items belonging to that group. This is an example of a rather common master/detail navigation pattern. In Figure 1, the <div> classed as “headertemplate” contains a <button> element bound to the group’s key. When the user taps or clicks the button, she moves to a page revealing the members of that group.

Figure 1 The Header and Item Templates for the ListView Control

<div class="headertemplate" data-win-control="WinJS.Binding.Template">
  <button class="group-header win-type-x-large win-type-interactive"
     data-win-bind="groupKey: key" 
     onclick="Application.navigator.pageControl
    .navigateToGroup(event.srcElement.groupKey)" 
     role="link" tabindex="-1"
     type="button">
    <span class="group-title win-type-ellipsis" data-win-bind=
      "textContent: title"></span>
    <span class="group-chevron"></span>
  </button>
</div>
<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
  <div class="item">
    <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>
</div>

The item template in Figure 1 consists of <div> tags that enclose an image and two text fields. Much of today’s data found in modern apps is graphic, so there’s an <img> element inside the item template. The sample data fills this element with an image that’s just a solid gray color. Figure 2depicts the default ListView from the Grid Layout.

The Default ListView from the Grid Template, with Heading and Navigation Buttons Marked in Red
Figure 2 The Default ListView from the Grid Template, with Heading and Navigation Buttons Marked in Red

After coding the item and group templates, it’s time to hook them up to some data.

Data and Data Binding with the ListView Control

JavaScript and JSON go hand in hand (JSON is JavaScript Object Notation, after all), so once you’ve retrieved some JSON data, just stuff it into an array and the Windows.Binding.List object turns it into a usable data source for the ListView. In other words, you don’t directly tie the ListView to an array or data source, meaning the List object serves as an intermediary between the ListView and the data source. This is because the List object transforms the data into something the ListView knows how to use—the ListView itself only defines the look and layout of the grid. The List object also provides methods for searching, sorting, adding and deleting members of the underlying array.

Examining the \js\data.js file uncovers a Data namespace as well as the arrays making up the sample data. The crucial takeaway is that the two arrays blend to form a master/detail relationship. The group property of each object in the sampleItems array (details) refers to its group in the sampleGroups array (master), as shown in Figure 3.

Figure 3 Sample Data in Array Form in the Grid Project Template

var sampleGroups = [
  { key: "group1", title: "Group Title: 1", 
     subtitle: "Group Subtitle: 1",
     backgroundImage: darkGray, description: groupDescription },
  { key: "group2", title: "Group Title: 2", 
     subtitle: "Group Subtitle: 2",
     backgroundImage: lightGray, description: groupDescription },
  { key: "group3", title: "Group Title: 3", 
     subtitle: "Group Subtitle: 3",
     backgroundImage: mediumGray, description: groupDescription }
];
var sampleItems = [
  { group: sampleGroups[0], title: "Item Title: 1",
    subtitle: "Item Subtitle: 1", 
    description: itemDescription,
     content: itemContent, backgroundImage: lightGray },
  { group: sampleGroups[0], title: "Item Title: 2",
     subtitle: "Item Subtitle: 2", 
     description: itemDescription,
     content: itemContent, backgroundImage: darkGray },
  { group: sampleGroups[0], title: "Item Title: 3", subtitle:
     "Item Subtitle: 3", 
     description: itemDescription,
     content: itemContent, backgroundImage: mediumGray },
  { group: sampleGroups[1], title: "Item Title: 1", subtitle:
     "Item Subtitle: 1", description: itemDescription,
     content: itemContent, backgroundImage: darkGray },
  { group: sampleGroups[2], title: "Item Title: 2", subtitle:
     "Item Subtitle: 2", description: itemDescription,
     content: itemContent, backgroundImage: mediumGray },
];

Of course, you’ll replace the sample data with your own by building your own arrays, accessing JSON or XML data, or perhaps by calling a Web service. You aren't tied to using the Data namespace and instead can define your own..

Near the top of the data.js file is the following line of code:

var list = new WinJS.Binding.List();

This list variable is a container for an array. You can add an array to the List by passing it into the List’s constructor method or by using the push method:

generateSampleData().forEach(function (item) {
  list.push(item);
});

Doing this fills the list with the array data, and you’re now ready to associate the list and the ListView. If you’re sticking with the default template code, you should perform this association when the app first loads, in the _initializeLayout function of the \js\default.js file, as shown here:

listView.itemDataSource = Data.items.dataSource;
listView.groupDataSource = Data.groups.dataSource;

Of course, depending on the size of your data, the load time may vary, so you might need to modify the loading process. Use your best judgment about loading data into memory, keeping in mind the importance of performance to users.

Notice that the item and group data sources are set to the Data.items.dataSource and Data.groups.dataSource, respectively. The members named “items” and “groups” of the Data namespace refer back to the functions that have created the array containing the data (that is, groupedItems). The Data namespace declaration in the \js\data.js file reflects this notion and shows other public members in the namespace for working with data:

WinJS.Namespace.define("Data", {
  items: groupedItems,
  groups: groupedItems.groups,
  getItemReference: getItemReference,
  getItemsFromGroup: getItemsFromGroup,
  resolveGroupReference: resolveGroupReference,
  resolveItemReference: resolveItemReference
});

The items and groups members of the Data namespace point to the groupedItems object, which has constructed the data properly. Everything in the Data namespace you’ve seen so far is included in the Visual Studio project templates. If you choose to start with a blank project, you’ll need to mold the data yourself by creating similar data-­access methods instead of relying on the Data namespace members.

At this point, the ListView is complete with data and bindings set up. You can bind properties of the objects in the data source to HTML elements by using the data-win-bind attribute, as shown here:

<h4 class="item-title" data-win-bind="textContent: title"></h4>

The preceding line of code binds the title property to the <h4> element as part of its text. Figure 1 and Figure 2 have more samples of the data-win-bind attribute in action.

Now that you have the ListView and data access ready, it’s time to move on to styling the ListView.

Style the ListView Control

Presentation is all about style. The WinJS libraries contain a complete set of CSS rules with predefined styles you can overwrite to mold the ListView in a variety of ways. If you’re unfamiliar with styling WinJS controls, see my October 2013 article, “Build a Responsive and Modern UI with CSS for WinJS Apps,” at msdn.microsoft.com/magazine/dn451447. You can style the entire ListView by overwriting the .win-listview CSS class. Along with styling the ListView, you can set the constituent pieces of the ListView using the following class selectors:

  • .win-viewport: Styles the ListView’s viewport. The viewport is where the scrollbar sits.
  • .win-surface: Styles the scrollable area of the ListView. This area moves when a user scrolls.

There are two ways to style items in a ListView. You can apply styles to the item template via the .win-item class, or you can override the .win-container class. Keep in mind that each item in a ListView comprises multiple HTML elements (refer to Figure 1 to view these elements). As you can see from Figure 1, the <div> elements that make up the item template contain an .item, .item-image, .item-overlay, .item-title and .item-subtitle class. You’ll find none of these defined in the system style sheets (that is, ui-light and ui-dark), as these are for you to style.

You should be aware of a handful of gotchas involved with styling, especially concerning when to apply margins and padding to the ListView control. You can review all the ins and outs of styling the ListView in the Dev Center for Windows Store apps at bit.ly/HopfUg. Don’t forget to create styles for all the various view states that your app might need.

Windows 8.1 includes some styling changes to the ListView concerning child/descendant selector specificity. This is because a new node belongs to the internal tree structure of the page, so you must update your CSS selectors to contain the .win-itembox class selector, like this: .win-container | .win-itembox | .win-item.

Respond to View State Changes in the ListView

Responding to the new Windows 8 snap and filled views is important for passing the Windows Store certification process. The snap view, along with the full and filled views, is how users can arrange multiple Windows Store apps on the screen. In Windows 8, users may resize up to two open app windows, one in filled view and one in snap view. In Windows 8.1, the maximum number of windows increases to four and there are more options for app display. These views are called tall or narrow in Windows 8.1, and are slightly different than the snap and filled views of Windows 8.

This means you must code the ListView control to change its format in response to changes in app view states. This is a process called responsive design, and you can achieve it by using CSS media queries. For a primer on CSS media queries, see my blog post, “Create mobile site layouts with CSS Media Queries,” at bit.ly/1c39mDx.

Media queries shape the ListView control to fit different view states in a way that makes sense for the varying screen sizes and orientations that go with each view. When switching to tall views, the ListView needs to turn into a list, as shown here:

listView.layout = new ui.ListLayout();

Later, when the user switches back to the original view state, you must set the ListView back to a grid:

listView.layout = new ui.GridLayout({ groupHeaderPosition: "top" });

If you want to change styling in the items in the ListView when the screen changes, add CSS to this media query in the \css\default.css file:

@media screen and (-ms-view-state: snapped) {...}

You don’t need a media query for full or filled views, as those use the default style sheets. However, you can use different media queries for a variety of screen sizes if needed.

ListView and Semantic Zoom

The reimagining of Windows in version 8 entails new ways to visualize, navigate and search data. This means you need to think differently about how to approach search. Instead of users having to type phrases into search boxes and sift through lists of results, they can now use semantic zoom to condense the data into digestible sections.

Semantic zoom lets the user search for things by using a pinch gesture (or Ctrl + mouse wheel) to pan or zoom out and observe the data in an aggregate format. For example, the Windows Start page behaves this way by showing users all available apps when they zoom out. Using semantic zoom in your app is easy, because it’s just a control for WinJS:

<div data-win-control="WinJS.UI.SemanticZoom">
  <!-- The control that provides the zoomed-in view goes here. -->
  <!-- The control that provides the zoomed-out view goes here. -->
</div>

The SemanticZoom control is simply a wrapper for a ListView or two, or perhaps the HTML Repeater control new to Windows 8.1.

Odds and Ends About the ListView

Don’t use the ListView as a general-purpose layout control. Use the CSS box model for that instead. In Windows 8.1, you should consider whether you’re better off using a ListView control or a Repeater control. A Repeater control is better if you don’t require a lot of functionality from the control and just need to repeat the same HTML design multiple times. At the time of this writing, Windows 8.1 is in preview, so there could be a few other changes to the ListView as well as other Windows Store app API components. For more information on Windows 8.1 API changes, see the Dev Center documentation at bit.ly/1dYTylx.


Rachel Appel is a consultant, author, mentor and former Microsoft employee with more than 20 years of experience in the IT industry. She speaks at top industry conferences such as Visual Studio Live!, DevConnections, MIX and more. Her expertise lies within developing solutions that align business and technology focusing on the Microsoft dev stack and open Web. For more about Appel, visit her Web site at rachelappel.com.

Thanks to the following technical expert for reviewing this article: Eric Schmidt (Microsoft)
Eric Schmidt is a content developer in Microsoft’s Windows Developer Content team, writing about the Windows Library for JavaScript (WinJS). Previously, he built code samples for the apps for Office platform while in the Microsoft Office Division. Otherwise, he spends time with his family, plays string bass, builds HTML5 video games or blogs about plastic building toys (historybricks.com).