Corrado's Blog 2.0

Online thoughts of a technology funatic

WinJS Custom Controls

Controls are the basic blocks of any application, you use controls everywhere and also HTML Metro apps are part of the game, you add a control inside a HTML Metro page just placing a <div> with a special “data-win-control” attribute in it:

here’s an example:

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

If you have pages (even in different applications) that need some special kind of functionality paired with some custom UI, custom controls allows you to reach the “write once, use everywhere” paradigm (unless you like reinventing the wheel of course…)Let’s see how you can create your own custom control and use it inside a HTML Metro application, simulating a simple custom countdown control.

Step 1: Design the user interface

While not strictly a requirement I personally like to start from the appearance of my control, so I fire up Expression Blend and start design it:


I’ve highlighted the HTML representing my control’s UI and, on right side, associated CSS, question now is: how do we turn it in a WinJS custom control?

Step2: Define public interface

The countdown control will expose:

  • initialValue property: will be initialized with countdown initial value
  • start method: begins countdown
  • countdownexpired and coundownstarted events

Step3: The code

below is the control’s code contained in a separate countdown.js file:

//Countdown control
(function (winJs) {
    var _events = ["countdownexpired", "coundownstarted"];

    WinJs.Namespace.define("MyApp.Controls", {
        Countdown: WinJs.Class.define(function (element, options) {
            if (!element) throw "element must be provided";
            options = options || {};
            this._element = element;
            this._element.winControl = this;
            winJs.UI.setOptions(this, options);
                //Private members
                _element: null,
                _cdn_host: null,
                _cdn_content: null,
                _timerId: 0,
                _progress: 0,
                _buildVisualTree: function () {
                    this._cdn_host = document.createElement("div");
                    this._cdn_host.className = "cdn-host";
                    this._cdn_content = document.createElement("span");
                    this._cdn_content.className = "cdn-content win-type-xx-large";
                _onTick: function () {
                    this._cdn_content.innerText = this._progress;
                    if (this._progress === 0) {
                        this._timerId = 0;

                //Public members
                element: {
                    get: function () { return this._element; }
                initialValue: {
                    get: function () { return this._cdn_content.innerText; },
                    set: function (value) {
                        this._cdn_content.innerText = value;

                //Play advertising
                start: function () {
                    if (this._timerId === 0) {
                        this._progress = this.initialValue;
                        this._timerId = setInterval(this._onTick.bind(this), 1000);

    winJs.Class.mix(MyApp.Controls.Countdown, winJs.Utilities.eventMixin);
    winJs.Class.mix(MyApp.Controls.Countdown, winJs.Utilities.createEventProperties(_events));

Let’s dissect it:

A WinJS custom control is just a class that has a constructor accepting two parameters: the element decorated with data-win-control attribute and optional options object containing control’s initialization parameters.

Our control will be contained inside a MyApp.Controls namespace.

Inside constructor I associate passed element with control’s element property and I also add associate control’s instance with a conventionally named winControl property appended to passed element so that it can easily accessible from page’s javascript code.

The buildVisualTree function uses javascript to recreate control’s DOM and appends it to passed element while setOptions is a WinJS helper method that associates passed options to control so that it can be correctly initialized.

Since the control exposes events we finally use a couple of WinJS helper methods to ‘mix’ control’s class with a class defined inside WinJS framework to add all stuff required to handle and raise events (like onXYZ methods or addEventListener/removeEventListener support)

The rest of the code is just countdown code implementation, nothing really new here.

Step 4: Using the control

To embed the code the control inside a HTML page we use exactly the same approach used for any WinJS control: add both required javasript and css references and decorate placeholder div with appropriate attributes, here’s the complete HTML page content:

    <meta charset="utf-8" />

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0.RC/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0.RC/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0.RC/js/ui.js"></script>

    <!-- DemoCustomControl references -->
    <link href="/css/default.css" rel="stylesheet" />
    <link href="/countdown.css" rel="stylesheet" type="text/css">
    <script type="text/javascript" src="js/controls/countdown.js"></script>
    <script src="/js/default.js"></script>

        WinJS.Utilities.ready(function () {
            var countdown = document.getElementById("countdown1");
            countdown.winControl.addEventListener("countdownexpired", function () {
                var msg = document.getElementById("result");
                msg.textContent = "done!";
            }, false);

            document.getElementById("start").addEventListener("click", function () {
            }, false);

        }, true).done();

        <div id="countdown1" data-win-control="MyApp.Controls.Countdown" data-win-options="{initialValue:4}">
        <button id="start">Start</button>
        <div id="result"></div>

A couple of notes:

  • we invoke WinJS.UI.processAll() method to force ‘transformation’ of ‘countdown1’ div into countdown control
  • we use WinJS.Utilities.ready() function to be sure that DOM tree is available when code runs (something that JQuery users know quite well).
  • note how countdown control is initialized using data-win-options attribute to 4 seconds.

Pressing start you will now see countdown starting and a message appearing at the end.< I found little documentation about creating custom control, that’s the reason of this post, if you want to know more I recommend this Build session:

Welcome to version 2.0

Welcome to my new home, relocation is not yet complete, still missing some pieces of furniture and paintings, but at least it is habitable :)
Ok, let’s keep moving things…