DCSIMG
How to Write a WinJS Custom Control - Gil Fink's Blog

Gil Fink's Blog

Fink about IT

News

Microsoft MVP

My Facebook Profile My Twitter Profile My Linkedin Profile

Locations of visitors to this page

Creative Commons License

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.
© Copyright 2013 Gil Fink

Hebrew Articles

Index Pages

My OSS Projects

English Articles

How to Write a WinJS Custom Control

How to Write a WinJS Custom Control

Lately, I was involved in a few Windows 8 projects. One of the questions that I am being asked from time to time was how to write your own Windows Store app custom control with WinJS library. This post will try to give you a head start for your custom control library. During the post you will build an autocomplete control step by step and learn a few WinJS concepts on the way. So let get started.

The WinJS.Namespace Object

The first thing to do when you write your own controls is to put them inside their own namespace. Namespaces help to group a set of identifiers into a logical group. Those identifiers can be classes, functions or any other development language structures that you wish to group inside the namespace. For more details about  JavaScript namespaces go to the following link.

WinJS includes a Namespace object that can help you define namespaces. You will use the WinJS.Namespace.define function which receives two parameters: the namespace name and an object populated with the namespace’s identifiers. The following example defines a new namespace called MyApp.UI:

WinJS.Namespace.define("MyApp.UI", {
   // identifiers
});

WinJS.Namespace object also include a defineWithParent function to define namespace hierarchies but in this example I don’t use it.

Defining the Control Class

So now we have a namespace, what's next? creating a control class.

Since JavaScript doesn’t include a class concept you can mimic that behavior using constructor functions and prototypical inheritance. Luckily, WinJS includes a Class object that exposes functions to define, derive or mix JavaScript “classes”.

In order to define a class, you will use the WinJS.Class.define function. The function gets three parameters: a constructor function to initialize objects, an instance members object to add to every created instance and a static members object which will be added to the prototype of the class. Lets define the Autocomplete class inside the previously created namespace:

WinJS.Namespace.define("MyApp.UI", {
        Autocomplete: WinJS.Class.define(function (element, options) {
            // constructor function body
        }, 
        { // instance members },
        { // static members });
});

As you can see the define function gets all the three parameters. In the constructor function you will get two parameters which are the element for the control and an options object to configure the control. The two parameters are mandatory for building a WinJS control since they are mapped to the data-win-control and data-win-options HTML attributes of the element when the processAll function is called.

Adding Control functionality

Now that we have our template for the control class, lets create its functionality. Before we write any code, lets understand what we expect from the control. The control needs to create a datalist element on the fly and attach it to an input type (if you want to read about the new HTML5 datalist element, you can go to the following link). The control also needs to get as input an option list that will be shown as the autocomplete list. So lets write the code:

(function (WinJS) {
    WinJS.Namespace.define("MyApp.UI", {
        Autocomplete: WinJS.Class.define(function (element, options) {              
            if (!element || element.tagName.toLowerCase() !== "input") throw "input type must be provided";
            options = options || {};
            this._setElement(element);
            this._setOptionList(options.optionList);
            this._element.winControl = this;
            WinJS.UI.setOptions(this, options);
            this._createDataList();            
        },
            {
                //Private members
                _element: null,
                _optionList: null,
                _setElement: function (element) {
                    this._element = element;
                },
                _setOptionList: function (optionList) {
                    optionList = optionList || [];
                    this._optionList = optionList;
                },
                _createDataList: function () {
                    var i = 0,
                        len = this._optionList.length,
                        dl = document.createElement('datalist');
                    dl.id = 'dl' + this._element.id;
                    this._element.setAttribute("list", dl.id);
                    for (; i < len; i += 1) {
                        var option = document.createElement('option');
                        option.value = this._optionList[i];
                        dl.appendChild(option);
                    }
                    document.body.appendChild(dl);
                },
 
                //Public members
                element: {
                    get: function () {
                        return this._element;
                    }
                }
            })
    });
}(WinJS));

As you can see, the constructor function first checks whether the element is an input type. It also sets the element and the option list which is supposed to be supplied in the option object. The last thing it does is to create the datalist element. In the instance member object you divide the functions and properties to a private and public member section. This division is only logical (and marked with comments) and as you can see private members gets the underscore character before their name. The main functionality here is the _createDataList function which handle the creation of the datalist and sets the input type list attribute to the list id. All the other functions are straight forward.

Using the Control

Now that we have the control, lets use it. In the example app I added a data.js file under the js folder and wrote the following code inside of it:

(function () {
    "use strict";
 
    WinJS.Namespace.define("Data", {
        cities: ["Seattle", "Las Vegas", "New York", "Salt lake City"]
    });
})();

I could get any data from any other source (cloud, service, storage) but I wanted the example to be simple.

In the home.html file located in pages/home folder I added a text input type which is configured using the data-win-control and data-win-options attributes:

<input type="text" name="txtCities" id="txtCities" data-win-control="WinJS.UI.Autocomplete" 
   data-win-options="{ optionList: Data.cities }"/>

Don’t forget to add the script tags for the autocomplete.js file and data.js file in order for the example to work.

Now everything is set and you can run the app and see the result:

Autocomplete WinJS Custom Control

The full example can be downloaded from here.

Summary

WinJS comes with a lot of built-in controls such as the FlipView, ListView ToggleSwitch and many more. On the other hand, sometimes it is necessary to build your own custom controls. In this post you learned the basics of creating your own WinJS custom control.

Comments

How to Implement a Custom WinJS Control in Windows 8 | SELA Blog News | Scoop.it said:

Pingback from  How to Implement a Custom WinJS Control in Windows 8 | SELA Blog News | Scoop.it

# September 24, 2012 7:08 PM

eladkatz said:

good post :)

# September 24, 2012 11:31 PM

Gil Fink said:

@eladkatz,

10X :)

# September 27, 2012 8:58 AM

Jon-Erik said:

Could you provide an example of how to use a remote source as data source?

# October 22, 2012 9:48 PM

Gil Fink said:

@Jon-Erik,

You can add a data source public member that can be set to the remote data. You can pass a promise that retrieve the remote data as one of the options and create the datalist after the promise complete. There are other various things that you can do.

# October 29, 2012 2:41 PM

Gil Fink's Blog said:

How to Write a WinJS Custom Control – Take Two In a previous post , I showed how to create a WinJS custom

# October 29, 2012 3:26 PM

How to Write a WinJS Custom Control - Gil Fink's Blog | WinJS Tutorial Advanced | Scoop.it said:

Pingback from  How to Write a WinJS Custom Control - Gil Fink's Blog | WinJS Tutorial Advanced | Scoop.it

# November 1, 2012 6:22 PM