WinRT JavaScript - WinControls
Written by Ian Elliot   
Article Index
WinRT JavaScript - WinControls
Controls in code

If you are building an HTML5 app specifically for Windows 8 there is a lot to be gained in functionality by using the Windows extensions and giving your app the full Metro style. Microsoft's custom controls are  easy to use once you know how they work.

Creating JavaScript/HTML5 Metro Applications
Chapter List

In the first chapter we looked at the simplest sort of JavaScript application you could construct - basically just an HTML5 page with some code.

If you want to remain platform-independent then this is all you need to know and you need to keep away from the Windows extensions. In particular, you need to avoid using the WinControls. If you are building an app specifically for Windows 8, however, there is a lot to be gained in functionality by making you app have the Metro style.

So let's take a look at the way that this all works.

The controls library

The first thing you need to do is to add a reference to controls.js to your project so that the appropriate JavaScript is loaded.

The minimum set of libraries to you need to make use of the WinControls is:

<script type="text/javascript"
       src="/WinJS/js/base.js">
</script>
<script type="text/javascript"
       src="/WinJS/js/ui.js">
</script>

The ui.js library is where the code that implements the and it provides many of the objects needed to implement the UI, including event handlers.

The above scripts need to be loaded as part of the default.html files header.

How controls work

How do you add controls to HTML?

You can't create new tags for them because HTML isn't extensible like other markup languages. What you can do is to use a simple tag like a <div> and augment it with the help of JavaScript.

The <div> simply marks the location of the JavaScript generated control in the rest of the HTML generated page. This is a very standard way to creating new controls and you will encounter it in lots of other places. Microsoft has implemented this approach to JavaScript controls in a fairly standards- compliant way by making use of data- attributes. These are the recommended way of adding custom attributes to tags.

So, for example, to create a Rating control you would add:

<div data-win-control="WinJS.UI.Rating">
</div>

at the location in the HTML that you want the control to appear.

What happens is that, when the DOM has finished loading, the JavaScript scans the DOM looking for tags with data-win-control properties. When it finds one, it injects the necessary objects into the DOM to create the control and generates a JavaScript object to represent the control in the program. Notice that in this scheme there are two objects that represent a control - a DOM object and a JavaScript object. It is important not to get confused between the two.

So when does the JavaScript scan the DOM looking for data-win-control attributes?

The answer is when you call the:

WinJS.UI.processAll();

function. This is the function that scans the DOM for the data-win- attribute and processes it to create the component.

You can call the processAll function at any point after the DOM is completely loaded and there are lots of possibilities for when to do this.

When an app is launched the sequence of events fired is:

  1. DOMContentLoaded
  2. activated (also known as mainwindowactivated)
  3. window.load

The DOMContentLoaded is the even that you can use for any work you need to do on the UI. This should be one-time initialization as the event doesn't fire when the app is reactivated. In this case only the activated event fires.When the app is refreshed only the DOMContentLoaded and window.load events fire.

What this means is that you should put anything that has to deal with restoring the state of the app into the activated event handler and any permanent setup actions that don't need to be repeated in the DOMContentLoads event handler, or perhaps the window.loaded event handler.

In other words, we should put the call to processAll in the DOMContentLoaded event handler. Howeverthe Blank Application template places the call in the onactivated handler and we might as well leave it there:


app.onactivated = function (eventObject) {
 if (activation is launch){

  other code

  WinJS.UI.processAll();
 }
};

 

If you now run the program you will see a default ratings control:

 

ratings

 

Notice that this is all standard HTML5 and you could use the same techniques to implement your own custom controls if you were prepared to write the necessary JavaScript. Notice however that using a WinJS control does mean that your app will only work under WinRT so you can't claim to be writing code that will run anywhere.

Parameters

What about setting some parameters of the displayed control?

This is also easy as there is another data- attribute that you can set to indicate that the processAll function should set parameters.

For example, the Ratings control has a maxRating property and this can be set using HTML by:

<div id="rating1"
   data-win-control="WinJS.UI.Rating"
   data-win-options="{maxRating:10}" >
</div>

Now if you run the program you will discover that the Rating control is displayed with ten stars.

The general idea is that to set properties on the control you set data-win-options to a JSON style object that consists of property:name:value pairs. When processAll reads the data-win-options attribute it simply uses the JSON object to initialize all of the properties of the control to the set values.

For example, as well as maxRating, the Rating control also offers the userRating property which sets the number of stars that are set. You can initialize both properties using:

<div id="rating1" 
data-win-control="WinJS.UI.Rating"
data-win-options="{maxRating:10,
userRating:8}" >
</div>

ratings2

 

Once you have seen the basic mechanism, it is fairly easy to initialize any control properties. It is worth noting that some properties are themselves objects, and so you can have something like:

{property1:{property2:value,
property3:value...}}

which sets property1.property2 to value and so on.