November 2012

Volume 27 Number 11

JavaScript - Building and Using Controls in Windows Store Apps with JavaScript

By Chris Sells | November 2012

In a previous article, “Data Binding in a Windows Store App with JavaScript,” we dug into the Windows Library for JavaScript (WinJS) and its support for data binding. When using data binding, it’s often in the context of a control, which is why we spent so much time digging into the care and feeding of the ListView control (you can see that article at msdn.microsoft.com/magazine/jj651576). In this article, we’re going to take a quick tour through the controls available to you as a JavaScript programmer building Windows Store apps. And, if those controls don’t meet your needs, we’ll show you how to build your own.

When using JavaScript to build controls in a Windows Store app, you have access to controls in several families:

  • HTML5 Elements: HTML5 elements are controls in the sense that they’re reusable chunks of UI and behavior, for example, <progress /> and <a />.
  • WinRT Controls: Controls exposed as Windows Runtime (WinRT) classes projected into JavaScript, such as Windows.UI.Popups.PopupMenu.
  • WinJS Controls: Controls implemented as JavaScript classes, such as WinJS.UI.ListView.
  • CSS Styles: CSS provides several styles that allow you to lay out your content items as if they were control containers, for example, column-count: 4.

In this article, we’ll focus on the first three categories of controls.

HTML5 Elements

Because Windows Store apps built with JavaScript are based on Web technology, all HTML5 elements work just fine, as Figure 1 shows.

HTML5 Controls Available to Your Windows Store Apps Built with JavaScript
Figure 1 HTML5 Controls Available to Your Windows Store Apps Built with JavaScript

The details of HTML5 elements are beyond the scope of this article, but we recommend your friendly neighborhood HTML5 documentation for more information. Also, the sample used to create Figure1 is provided with the accompanying source code download.

WinRT Controls

The Windows Runtime provides all kinds of functionality in all kinds of areas, but in the case of controls, it provides only two:

  • Message Dialog: A message with an optional title.
  • Pop-up Menu: A menu limited to six or fewer items.

The message dialog is invoked using the MessageDialog function:

var popups = Windows.UI.Popups;
var mb = new popups.MessageDialog("and welcome to my message box!", "Hello!");
mb.showAsync();

The MessageDialog class has a showAsync method that returns a promise, just like all the other async operations a Windows Store app built with JavaScript has at its disposal. In this case, however, we’re ignoring the promise because we often don’t care when a message dialog goes away. Figure 2 shows the result (using “MessageBox,” which is the previous terminology for MessageDialog).

The WinRT Message Dialog
Figure 2 The WinRT Message Dialog

The PopupMenu class is used similarly:

var popups = Windows.UI.Popups;
var menu = new popups.PopupMenu();
menu.commands.push(new popups.UICommand("one", null, 1));
menu.commands.push(new popups.UICommand("two", null, 2));
menu.showAsync({ x: 120, y: 360 }).done(function (e) {
  // Do something with e.label and/or e.id
  ...
});

In this example, after creating a PopupMenu object, we provide two UICommand objects, each with a label and optional callbacks and id parameters. We’re not using the callback for each of the commands in this example because we’re capturing the event parameter in the “done” completion method. A pop-up menu looks like you’d expect, as shown in Figure 3.

The WinRT Pop-up Menu
Figure 3 The WinRT Pop-up Menu

Remember that as of this writing, the context menu is limited to only six items.

WinJS Controls

Although HTML5 controls are rich and varied, the set won’t be extensible until the World Wide Web Consortium decides to add a new element tag and the browser vendors decide to implement it. Likewise, the set of WinRT controls is also not extensible (although you can build non-UI Windows Runtime Components). For the extensible set of controls that have been built specifically with Windows Store apps in mind, the sweet spot is the set provided by WinJS.

A WinJS control is a control implemented in JavaScript that provides a certain signature in the constructor function:

function MyControl(element,
    options) {...}

The element argument is the HTML Document Object Model (DOM) element that’s meant to act as the host for the control’s content, often a div. The options argument is a JavaScript object used to provide optional configuration arguments, such as the ListView itemDataSource property.

To see a WinJS control in action, let’s consider a div meant to act as the host of a DatePicker control:

<div id="datePickerDiv"></div>

With this in place, we can create a DatePicker as easily as this:

var datePicker = new WinJS.UI.DatePicker(datePickerDiv);

And the output is a brand-new DatePicker control, as shown in Figure 4.

Output of the DatePicker Control
Figure 4 Output of the DatePicker Control

If we’d like to configure a control, we can pass in a set of options:

var datePicker = new WinJS.UI.DatePicker(datePickerDiv, { current: "6/2/1969" });

In the case of the DatePicker, the current option lets us set the currently displayed date, as shown in Figure 5.

Setting the Currently Displayed Date
Figure 5 Setting the Currently Displayed Date

Once you’ve got a control associated with your HTML5 element, you can grab the control using the winControl property:

var datePicker = datePickerDiv.winControl; // Magical well-known property name
datePicker.current = "5/5/1995"; // Now we're talking to the control

Further, once you’ve got the control, you can get back to the associated HTML5 element with the element property:

var datePickerDiv = datePicker.element;
datePickerDiv.style.display = "none";
// Now we're talking to the HTML element

In addition to allowing for programmatic creation, each control also provides for declarative creation via the data-win-control and data-win-options attributes, as we’ve seen:

<div id="datePicker2"
  data-win-control="WinJS.UI.DatePicker" data-win-options=
  "{current: '6/2/1969'}" ></div>

The data-win-control attribute is the name of the constructor function to call. As in data binding, which requires a call to WinJS.Binding.processAll for the data-win-bind attributes to be parsed (see our previous article), the data-win-control property needs a call to WinJS.UI.processAll for it to be parsed and the controls to be created. This is why you’ll see a call to WinJS.UI.processAll in all of the generated project template code.

The data-win-options string is parsed as a less-powerful JavaScript object-initialization syntax. For example, you’ll notice that instead of setting the current option for the DatePicker control by creating a Date object, we passed the string directly. That’s because the options parser doesn’t understand the “new” keyword—it only works with static data. However, because the DatePicker and the other WinJS controls are expecting to be created in a declarative way, they make special allowances for the limitations of the options parser, which—in this case for the DatePicker—means taking in a string and parsing it as a Date object for you.

Every control has a different set of options, and we’ll refer you to the documentation to see which controls have which options. Figure 6 shows a list of the built-in WinJS controls.

Figure 6 The WinJS Controls

Name Description Class
App Bar Displays app-level commands in a toolbar WinJS.UI.AppBar
Date Picker Displays a UI to pick a date WinJS.UI.DatePicker
Flip View Flips through a set of content, one item at a time WinJS.UI.FlipView
Flyout Displays an overlay with arbitrary content WinJS.UI.Flyout
List View Displays a collection of items in a list or grid, grouped or ungrouped WinJS.UI.ListView
Rating Displays a UI to rate something, for example, a movie WinJS.UI.Rating
Semantic Zoom Provides a UI to zoom from one ListView to another, for example, a grouped ListView zooming out to a list of groups WinJS.UI.SemanticZoom
Settings Flyout Provides a UI for configuration of app settings WinJS.UI.SettingsFlyout
Time Picker Displays a UI to pick a time WinJS.UI.TimePicker
Toggle Switch Displays a UI to pick between two choices WinJS.UI.ToggleSwitch
Tooltip (Rich) Displays a tooltip with arbitrary HTML content WinJS.UI.Tooltip
View Box Provides a logically fixed-sized region scaled to the available space WinJS.UI.ViewBox

Figure 7shows the WinJS controls in action.

The WinJS Controls in Action
Figure 7 The WinJS Controls in Action

You should feel free to mix and match HTML5 controls, WinRT controls and WinJS controls in your Windows Store app.

Or, if you don’t find the control you want on the list provided by HTML5, Windows Runtime or WinJS, you can build your own.

Custom Controls

As we mentioned, a WinJS control is just a function that provides a constructor of the following form:

function MyControl(element, options) {...}

Building such a control is a matter of implementing a function to create the HTML under the parent element passed in as the first argument and using the options object passed in as the second argument. For example, imagine that we wanted to build a little clock control such as that shown in Figure 8.

A Custom Clock Control
Figure 8 A Custom Clock Control

Assume we have a div all set to contain our clock control:

<div id="clockControl1"></div>

Just like the built-in WinJS controls, we’d like to be able to create an instance of a custom control, like so:

var clock = new Samples.UI.ClockControl(clockControl1, { color: 'red' });
clock.color = 'red'; // Can set options as part of construction or later

The name we’ve picked for our custom control is ClockControl from the Samples.UI namespace. Just as before, creating the control is a matter of passing in the containing element (clockControl1) and an optional set of name/value pairs for options. If later in the lifetime of the control we’d like to change one of the control’s options, we should be able to do so by setting an individual property value.

We’d also like to be able to create custom controls declaratively:

<script src="/js/clockControl.js"></script>
  ...
  <div id="clockControl2"
    style="width: 200px; height: 200px;"    
    data-win-control="Samples.UI.ClockControl"
    data-win-options="{color: 'red'}">  </div>

As part of our implementation, we’d like to make sure that the winControl and element properties are set up, that private members are marked appropriately and that events can be handled appropriately. As we dig into the implementation of the ClockControl, we’ll see how WinJS helps us implement these features.

Control Class First, we’ll need to make sure that the ClockControl makes it into the right namespace. Most modern languages have the concept of a namespace as a way of separating types, functions and values into separate named areas to avoid collisions. For example, if Microsoft provides a ClockControl type in WinJS 2.0, it’ll be in the WinJS.UI namespace, so it won’t collide with Samples.UI. In JavaScript, a namespace is just another object with constructors, functions and values, which you could populate like this:

// clockControl.js
(function () {
  // The hard way
  window.Samples = window.Samples || {};
  window.Samples.UI = window.Samples.UI || {};
  window.Samples.UI.ClockControl = 
    function(element, options) { ... };
})();

This works just fine. However, defining namespaces (and nested namespaces) is such a common thing to do that WinJS (like many JavaScript libraries) provides a shortcut:

// clockControl.js
(function () {
  // The easy way
  WinJS.Namespace.define("Samples.UI", {
    ClockControl: function (element, options) { ... };
  };
})();

The define function in the WinJS.Namespace namespace allows for defining a new namespace, properly handling the parsing of dotted names for you. The second argument is an object to define the constructors, functions and values that we’d want to expose from this namespace, which is just the ClockControl constructor in our case.

Control Properties and Methods On our ClockControl type, we’d like to expose methods and properties, such as the color property. Those methods and properties could be instance or static, and they might be public or private (at least as “private” as Java­Script allows an object’s members to get). All of these concepts are supported via the correct use of the constructor’s prototype property and the Object.defineProperties method new to JavaScript. WinJS provides a shortcut for this, too, via the define method on the WinJS.Class namespace:

WinJS.Namespace.define("Samples.UI", {
  ClockControl: WinJS.Class.define(
    function (element, options) {...}, // ctor
  { // Properties and methods
    color: "black",
    width: { get: function () { ... } },
    height: { get: function () { ... } },
    radius: { get: function () { ... } },
    _tick: function () { ... },
    _drawFace: function () { ... },
    _drawHand: function (radians, thickness, length) { ... },
  })
});

The WinJS.Class.define method takes the function that acts as the constructor, but it also takes the set of properties and methods. The define method knows how to create a property from the get and set functions provided. Further, it knows that properties or methods prefixed with an underscore—for example, _tick—are meant to be “private.” JavaScript doesn’t really support private methods in the traditional sense—that is, we can still call the _tick method. However, they won’t show up in Visual Studio 2012 IntelliSense or in JavaScript for-in loops, which is at least a handy way to signal they aren’t meant for public consumption.

The constructor sets up the properties required to be a WinJS control, as shown in Figure 9.

Figure 9 The Constructor Sets up the Properties Required to Be a WinJS Control

WinJS.Namespace.define("Samples.UI", {
  ClockControl: WinJS.Class.define(function (element, options) {
    // Set up well-known properties
    element.winControl = this;
    this.element = element;
    // Parse the options; that is, the color option
    WinJS.UI.setOptions(this, options);
    // Create the drawing surface
    var canvas = document.createElement("canvas");
    element.appendChild(canvas);
    this._ctx = canvas.getContext("2d");
    // Draw the clock now and every second
    setTimeout(this._tick.bind(this), 0);
    setInterval(this._tick.bind(this), 1000);
  },
  ...
});

The first thing the constructor does is set up the well-known winControl and element properties so a developer can go back and forth between the hosting HTML5 element and the JavaScript control.

Next, the constructor handles the options. You’ll recall that the options can be specified as a set of name/value pairs or—using the data-win-options attribute from HTML5—a string. WinJS handles the parsing of the options string into a JavaScript object, so you can just deal with the name/value pairs. If you like, you can pull out individual properties, for example, the color property in our case. However, if you have a large list of options, the setOptions method in the WinJS.UI namespace will traverse all of the properties in the options object and set them as properties on your control. For example, the following blocks of code are equivalent:

// Setting each property one at a time
myControl.one = "one";
myControl.two = 2;
// Setting all properties at once
WinJS.UI.setOptions(myControl, {
  one: "one",
  two: 2,
});

After setting the control’s options, it’s the constructor’s job to create whatever child elements of the HTML5 parent element it needs to get the job done. In the case of the ClockControl, we’re using the HTML5 canvas element and a timer. The implementation of this control is just plain-old HTML and JavaScript, so it isn’t shown here (but it is available in the accompanying code download).

Control Events In addition to methods and properties, a control often exposes events. An event is some notification from your control that something interesting has happened, such as the user has clicked on the control or the control has reached some state that triggers some other kind of behavior in your program. Based on the example set by the HTML DOM, you’re going to want methods such as addEventListener and removeEventListener to allow developers to subscribe to whatever events your control exposes as well as corresponding onmyevent properties.

For example, if we wanted to expose an event from our sample ClockControl every 5 seconds, we’d expect to be able to subscribe to it programmatically:

// Do something every 5 seconds
window.clockControl_fiveseconds = function (e) {
  ...
};
var clock = new Samples.UI.ClockControl(...);
// This style works
clock.onfiveseconds = clockControl_fiveseconds;
// This style works, too
clock.addEventListener("fiveseconds", clockControl_fiveseconds);
Declaratively, we’d like to be able to attach to custom events, too:
<!-- this style works, three -->
<div data-win-control="Samples.UI.ClockControl"
  data-win-options="{color: 'white',
    onfiveseconds: clockControl_fiveseconds}" ...>
</div>

Enabling all three of these styles requires two things: the methods to manage event subscriptions (and for dispatching events when they occur) and a property for each event. Both of these are provided by the WinJS.Class namespace:

// clockControl.js
...
WinJS.Namespace.define("Samples.UI", {
  ClockControl: WinJS.Class.define(...);
});
// Add event support to ClockControl
WinJS.Class.mix(Samples.UI.ClockControl, 
  WinJS.UI.DOMEventMixin);
WinJS.Class.mix(Samples.UI.ClockControl,  
  WinJS.Utilities.createEventProperties("fiveseconds"));

The mix method of WinJS.Class allows you to mix in properties and methods provided by existing objects. In this case, the DOMEventMixin from WinJS.UI provides three methods:

// base.js
var DOMEventMixin = {
  addEventListener: function (type, listener, useCapture) {...},
  dispatchEvent: function (type, eventProperties) {...},
  removeEventListener: function (type, listener, useCapture) {...},
};

Once we mix in the methods from DOMEventMixin, we can create the properties for each of the custom events using the mix method with an object created by the createEventProperties method of WinJS.Utilities. This method produces the set of events methods for each of the comma-delimited event names you pass in, prepending the “on” prefix. With this set of properties and methods provided by these two calls to the mix method, we’ve augmented our custom control to support the fiveseconds event. To dispatch an event of this type from inside the control, we call the dispatchEvent method:

// clockControl.js
...
_tick: function () {
  var now = new Date();
  var sec = now.getSeconds();
  ...
  // Fire the 5 second event
  if (sec % 5 == 0) {
    this.dispatchEvent("fiveseconds", { when: now });
  }
},
...

Calling dispatchEvent takes two parameters: the name of the event and the optional details object available in the event itself. We’re passing in a single “when” value, but JavaScript being Java­Script, we could pass whatever we wanted. Accessing the event detail in the handler is a matter of pulling out the detail value of the event object itself:

// Do something every 5 seconds
window.clockControl_fiveseconds = function (e) {
  var when = e.detail.when;
  ...
};

The principles of defining WinJS controls that we’ve shown you—defining a class in a namespace, setting the winControl and element properties, processing the options object, defining properties and methods, and defining and dispatching custom events—are the exact same techniques that the WinJS team at Microsoft used to produce the WinJS controls themselves. You can learn a lot about how your favorite controls were built by reading the ui.js file provided with WinJS.


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.

Brandon Satrom is a program manager in the Kendo UI Division at Telerik. He is coauthor of “Building Windows 8 Apps with JavaScript” (Addison-Wesley Professional, 2012), from which this article was adapted. You can follow him on Twitter at twitter.com/BrandonSatrom.

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