WinRT JavaScript - WinControls
Written by Mike James   
Monday, 09 January 2012
Article Index
WinRT JavaScript - WinControls
Controls in code

Controls in code

The use of the data- attributes and processAll to add custom controls to the HTML markup is a useful way to create a more advanced UI and it extends HTML to have some of the characteristics of a more advanced markup language like XAML. However, you don't have to make use of any markup in an HTML5 app. All controls, native or custom, can be created in code.

For example, to add a Rating control in code all you have to do is make use of the specified constructor:

var object=new WinJS.UI.Rating(element,
options);

where element is the HTML element to be used to display the control and options specify the initial settings for the properties, if any.

For example, to add a Rating control at the position of a <div> we simply need to add a tag with an id that we can use to retrieve the element:

<div id="rating1"></div>

In the JavaScript program we now simply wait for the DOM to be loaded and retrieve the DOM object corresponding to "rating1". Next we simply use the constructor to build the control at the location of the <div>:

document.addEventListener("DOMContentLoaded", 
function (e) {
var element =
document.getElementById("rating1");
var rating = new WinJS.UI.Rating(element);
});


If you run this program you will see the default Rating control appear at the location of the <div>.

Notice that we no longer need processAll because this simply reads the DOM looking for data- tags and then does the same job of creating the control as we have just done explicitly using the constructor. Notice also that when we use the constructor we get the JavaScript object associated with the control automatically. If you create a control using HTML and processAll then you have to retrieve the JavaScript object manually if you require it using the getControl function - see later. 

You can use the second parameter in the constructor to set initial property values using the same format as in the data- attribute. For example, to set the maxRating and userRating properties you would use:

var rating = new WinJS.UI.Rating(
element,{maxRating:10,userRating:8});

Of course, as you have the JavaScript control object, you can set properties directly in the usual way. However, there is a complication in that some variables cannot be changed after the control has been created. For example, you cannot set maxRating but you can set userRating:

rating.userRating = 4;

This changes the number of stars displayed.

At this point you may be wondering how setting a property to a new value can trigger the update of the control? The answer is that modern JavaScript has getters and setters. That is, if you define a setter function, assigning a value to a property doesn't store the value - it calls the setter. In this case the setter function not only stores the new value, it also updates the control.

If you look at the code in the JavaScript library you will discover that it says:

userRating: {
set: function (value) {
if ((typeof value !== "number") ||
(value < 0) ||
(value > this._maxRating) ||
 (Math.floor(value) !== value)) {
   throw new Error(userRatingIsInvalid);
  }
this._userRating = value;
this._updateControl();
}
...

What this means is that when you write:

rating.userRating = 4;

the set function is called which checks that the value is valid, stores the value in an internal variable, and then updates the control. Notice the convention that internal variables begin with an underscore.

Similarly, a getter results in a function being called when you retrieve a value. The WinRT JavaScript libraries make a lot of use of getters and setters to check input values and to trigger updates. If you aren't familiar with getters and setters then look them up.

Of course, the rule that some properties have to be set by the constructor and cannot be changed subsequently, is one that is enforced by the way the setter for that property is written, i.e. Microsoft decides when a property would cause too much updating to be set after construction.

Code access to a markup control

There is one final aspect of working with a control in code that we need to cover. Suppose you have defined a control in HTML using the data- attribute. How do you work with it in code?

The answer is very easy.

First you have to retrieve the DOM element that the control is associated with and next you use this to retrieve the JavaScript object corresponding to the control.

For example, if a Rating control is defined using:

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

then we can modify the userRating using:

document.addEventListener("DOMContentLoaded", 
function (e) {
     WinJS.UI.processAll();
        var element =
document.getElementById("rating1");
        var rating =
WinJS.UI.getControl(element);
        rating.userRating = 4;
    });

If you run this program you should see four stars. However, there is a problem in that this code isn't quite correct. The problem is that processAll is asynchronous and it returns immediately even if it hasn't finished processing controls. What this means is that you shouldn't start setting properties on controls that might not have been created yet.

The proper way to do the job is to make use of the Promise object that the processAll function returns. This has a then method that accepts three functions: one that is run when complete; one that is run if there is an error; and one that is run as the asynchronous operation proceeds, i.e. a progress function.

So to do the job properly all we have to do is put the code that does the update into the first function specified in the then method:

document.addEventListener(
"DOMContentLoaded", function (e) {
WinJS.UI.processAll().then(
function () {
     var element =
document.getElementById("rating1");
     var rating =
WinJS.UI.getControl(element);
     rating.userRating = 3;
  });
});

 

For simplicity, the error and progress functions haven't been defined. In a real life program at least the error handler should be defined.

As you make more and more use of the WinRT JavaScript libraries you will become increasingly familiar with the idea of Promise objects and how to make use of them as part of the everyday asynchronous call.

Events

One of the common things that you have to do in code, no matter whether the control is created in code or in markup, is to attach an event handler. Each custom control supports a range of events and the procedure for dealing with them is the same in all cases.

First, you need the JavaScript object corresponding to the control. You can either get this from the constructor if the control is created in code, or via getControl if it is created in markup. Next, you simply use the addEventListener method to add the event handler.

For example, the Ratings control has a change event which is fired when the user tries to adjust a rating. To hook up an event handler all you have to do is:

WinJS.UI.processAll().then(function () {
var element =
document.getElementById("rating1");
var rating =
WinJS.UI.getControl(element);
 rating.addEventListener("change",
function () { ... });
});

You can, of course, create the event handler elsewhere in your code and add it by name, i.e. you don't have to use an anonymous function.

It is also possible to attach an event handler in markup or when you first create a control in code via the constructor. 

For example to set the change event handler in HTML you would use:

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

Notice that in this case the name of the event is onchange. The rule is that if a property starts with "on" then its value is assumed to be a function. In this case it is assumed that myChange is a global function defined in the default.js file or elsewhere.

Where next?

In this article you have seen the basic ideas that are involved in using the custom WinJS controls. The example control, i.e. Ratings, is fairly typical of the simple controls, but things do get a little more complicated when you start to work with layout controls and more complex list controls. In particular there is the way databinding works to find out about.

You can see a full list of the custom controls in the listing for the WinJS.UI name space which is currently at

http://msdn.microsoft.com/en-us/library/windows/apps/br229782.aspx


One control that is really worth getting to know first, however, is the Template which can be used to create customized HTML very easily.

More about templates in the next article.

Articles on WinRT JavaScript

  1. Getting Started
  2. WinControls (this article)
  3. Templates & Data Binding

 

Banner

 

espbook

 

Comments




or email your comment to: comments@i-programmer.info

 

To be informed about new articles on I Programmer, subscribe to the RSS feed, follow us on Google+, Twitter, Linkedin or Facebook or sign up for our weekly newsletter.

{maxRating:10,
userRating:8}


Last Updated ( Wednesday, 18 January 2012 )