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

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 />.

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.

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:

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).

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.

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:

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:

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.

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:

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.

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.

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:

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:

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

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:

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:

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:

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:

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:

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 Sellsis 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 Satromis 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.