WinJS: Writing code using the Windows Store library for Javascript

Part of the advantage of ramping up to write Windows Store apps is that you can utilize your existing knowledge of HTML, CSS and Javascript.

The Windows Library for JavaScript (referred to as WinJS) extends the support for Javascript in Windows Store apps, has a number of helper functions for common app development scenarios. In the article below, we’ll talk about how to get started with WinJS for creating custom types and namespaces, as well as handling and managing event listeners.

Defining and deriving types with WinJS.Class

In the sections below, we’ll talk about how you can use the define and derive methods in the WinJS library to quickly create your own custom types, and specify their property constructors.

WinJS.Class.define

The WinJS.Class.define function is a helper function for defining a JavaScript type. You supply a constructor function, a set of "instance" members (which are defined on the prototype of the type), and a set of "static" members (which are defined on the type itself).

The properties that are added to the prototype of an object appear on any object that is instantiated by calling its constructor function, but the properties added to the type directly belong only to the type itself.

For example, let’s say we want to define a class Robot, which has an instance property name and a static property harmsHumans. The modelName property belongs to the individual objects created with Robot(name)contstructor function, but the harmsHuman property is valid for all Robot objects.

Using WinJS.Class.define

Pure Javascript

var Robot = WinJS.Class.define( function(name) {

this.name = name;

},

{ modelName: "" },

{ harmsHumans: false });

varmyRobot = new Robot("Mickey");

myRobot.modelName = "4500";

Robot.harmsHumans = false;

function Robot(name) {

this.name = name;

}

Robot.prototype.modelName = '4500';

Robot.harmsHumans = false;

WinJS.Class.define offers helpful shortcuts for defining properties. In JavaScript you can customize the behavior of properties by using a property descriptor. WinJS.Class.define treats a given object as a property descriptor. For example, if you want to use a computed value for modelName, in JavaScript without Windows Library for JavaScript you need the following code:

Using WinJS.Class.define

Pure Javascript

var Robot = WinJS.Class.define(

function (name) { this.name = name; },

{

modelName: { get: function () { return this.computeModelName(); } }

}

);

Object.defineProperty(Robot.prototype, "modelName", {

get: function () { this.computeModelName(); }

});

This way, if you use WinJS to define your custom types in your Windows Store app, you can define the setters and getters of properties within the WinJS.Class.define code block.

WinJS.Class.derive

The WinJS.Class.derive is a similar helper function that you can use to derive one custom Javascript type from another. It behaves much like WinJS.Class.define, except that it uses the prototype that you provide to construct the derived type by calling Object.create.

The following code shows how to derive a SpaceRobot type from the Robot type.

varSpaceRobot = WinJS.Class.derive(Robot, function (name) {

this.name = name;

},

{ airSupply: "" },

{ saveSelf: true });

varmySpaceRobot = new SpaceRobot("Myra");

mySpaceRobot.airSupply = "oxygen";

var save = SpaceRobot.saveSelf;

Organizing your code with WinJS.Namespace

In addition to creating custom types, you might want to organize these types into your own custom namespace, so that you can reference them conveniently and consistently through your code.

When you create a type or other element in a namespace, you reference it from outside the namespace by using its qualified name: Namespace.Type.

NOTE: You should define your elements before you define the namespace, and simply add references to these elements inside the namespace definition. If you define your elements inside the namespace definition, you may try to use the this keyword to erroneously refer to other members of the namespace.

In general, the best way to define namespace members is to do so inside a module closure, defining the namespace elements first and then adding them to the namespace definition. The members must be defined before they are added to the namespace definition.

Let’s look at an example below:

function () {

var Robot = WinJS.Class.define(function (name) {

this.name = name;

},

{ modelName: "" },

{ harmsHumans: false, obeysOrders: true }

);

WinJS.Namespace.define("Robotics", {

Robot: Robot

});

}

As you can see, you should define your elements before you define the namespace, and simply add references to these elements in the namespace definition.

Later, to create a new object of the type Robot, you call the members of the Robotics namespace as follows

varmyRobot = new Robotics.Robot("Sam");

var harm = Robotics.Robot.harmsHumans;

You should not to refer to the namespace before it is defined. If you do so, as in the code below, you get the error "namespace name is undefined."

//Example of namespace defined in the wrong order

//first user defines type Robot

var Robot = WinJS.Class.define(function (name) {

this.name = name;

},

{ modelName: "" },

{ harmsHumans: false, obeysOrders: true }

);

//The user calls constructor function in Robotics namespace, without having first defined the namespace

varmyRobot = new Robotics.Robot("mike");

WinJS.Namespace.define("Robotics", {

Robot: Robot

});

//Bad robot!

You can also add properties and functions to a namespace multiple times if you need to, i.e. after you’ve already defined the namespace. For example, you might want to define a function in a different file from the one in which the rest of the namespace elements are defined to keep your code organized. You may even want to write that function once and then add it to several namespaces (in the separate file).

In the following code, WinJS.Namespace.define is called twice to add the getAllRobots function and the findRobot function to the Robotics namespace.

var Robot =WinJS.Class.define( function(name) {

this.name = name;

});

functiongetAllRobots() {

returnallRobots;

}

varallRobots = [

new Robot("mike"),

new Robot("ellen")

];

WinJS.Namespace.define("Robotics", {

Robot: Robot,

getAllRobots: getAllRobots

});

functionfindRobot(robotName) {

for (vari in allRobots) {

if (allRobots[i].name == robotName) {

returnallRobots[i];

}

}

}

WinJS.Namespace.define("Robotics", {

findRobot: findRobot

});

Nesting Namespaces

You can create nested namespaces by defining individual namespaces with dot notation, for example "Robotics.Search". (However, it's not a good idea to use a lot of nesting in your code, because nesting can make the code very complex.)

Here's an example of a nested namespace:

var Robot =WinJS.Class.define( function(name) {

this.name = name;

});

functionfindRobot(robotName) {

for (vari in allRobots) {

if (allRobots[i].name == robotName) {

returnallRobots[i];

}

}

}

varallRobots = [

new Robot("mike"),

new Robot("ellen")

];

functiongetAllRobots() {

returnallRobots;

}

WinJS.Namespace.define("Robotics", {

Robot: Robot

});

WinJS.Namespace.define("Robotics.Search", {

findRobot: findRobot

});

var robot = Robotics.Search.findRobot("mike");

The namespace examples above show how you can organize your types and their related functions in different ways using WinJS.Namespace.define

Adding functionality with WinJSmixins

Mixins are objects that implement a certain class of functionality. For example, in the Windows Library for JavaScript there are mixins that manage events and mixins that handle DOM binding.

Mixins aren't designed to be used directly, but you can use them to add functionality to your types. Mixins contain implemented functions that can be added to many types.

Think of a mixin as an abstract base class, which is not intended for direct consumption i.e. instantiation, without subclassing.Additionally, a class or object may "inherit" most or all of its functionality from one or more mixins, therefore mixins can be thought of as a mechanism of multiple inheritance.[RL1]

The examples below show how to extend our Robot class by creating our own mixins. This code shows how to define a Movable mixin that contains functions goForward, goBackward, turnRight, and turnLeft and use WinJS.Class.mix to add it to the Robot class. (NOTE: You need to add a DIV element with an ID of "div" to make this example work.)

WinJS.Namespace.define("Robotics", {

Robot: WinJS.Class.define( function(name) {

this.name = name;

},

{ name: name },

{ harmsHumans: false, obeysOrders: true })

});

var Movable = {

goForward: function () {

document.getElementById("div").innerText = "go forward";

},

goBack: function () {

document.getElementById("div").innerText = "go back";

},

turnRight: function () {

document.getElementById("div").innerText = "turn right";

},

turnLeft: function () {

document.getElementById("div").innerText = "turn left";

};

//here is Where we extend our Robot type be adding the functionality from Movable.

WinJS.Class.mix(Robotics.Robot, Movable);

varmyRobot = new Robotics.Robot("Mickey");

myRobot.goBack();

The example above shows how you can add custom functionality to your classes from mixins that you have defined. The Windows Library for Javascript has several out-of-box mixins which can help you with event management as well as binding to your objects.

When you run this code, you should see that the innerText value of the DIV is "got renamed".

NOTE: You must mix the WinJS.Utilities.eventMixin with the type before you use WinJS.Utilities.createEventProperties.

Adding DOMEventMixin to a type

WinJS.Utilities.eventMixin is useful for defining events on types that are dealt with completely in JavaScript. It isn't useful when you're working with events that are associated with DOM elements. Windows Library for JavaScript controls wrap and manipulate HTML elements. These controls often contain events that are based on the DOM events raised from their associated DOM elements. For example, when you use a DatePicker, you find it easier to respond to a change event from the DatePicker control rather than to track individual change events from the three select controls.

Associating events with the control type rather than the DOM element also protects the code from changes, for example if the implementation of the DatePicker changes the controls it contains.

The DOM event model allows for event propagation. DOM events are propagated up the DOM tree and can be handled at any level. This is useful when you have a lot of clickable elements. For example, you can put a single click handler function on the DIV element that contains the elements and then process all the click events from all the contained elements as they bubble up. For more information about DOM event handling, see Event capture and event bubbling.

To add this mixin to a type you have created, you must set a property named _domElement on the type. This is the field that the WinJS.UI.DOMEventMixin implementation looks for when it raises the event. It becomes the target node for the event.

The following code shows how to create a minimal control class on a DIV element and mix WinJS.UI.DOMEventMixin. You can then add an event listener for the click event and respond to it.

For this code to work, you need one DIV that has an ID of "div" and a second DIV that has an ID of "report".

Adding binding functionality with WinJS.Binding.mixin

To bind a user-defined object to an HTML element, you must make it observable, that is, capable of notifying listeners when its properties change. The WinJS.Binding.mixin provides this functionality. For an example, see How to bind a complex object.

In the addEventListener method, if you set the useCapture parameter to true, the order in which events are handled is top-down. That is, if there are event handlers for the specified event that belong to more than one element in the DOM tree, the handler belonging to the highest element in the tree is called first, and any handlers belonging to child elements are called after that. If you set the useCapture parameter to false, the handler that belongs to the target element is called first, and any handlers that belong to parent elements are called after that.

In this example, you create a WinJS.UI.DatePicker and add the same change handler function to the WinJS.UI.DatePicker and the document object. If you set the useCapture parameter to true, the handler on the document object is called first, then the handler on the WinJS.UI.DatePicker object.

In an event, the this keyword refers to the target of the event, so you should see "change event for [object Document]" and then "change event for [object HTMLDivElement]". If you set the useCapture parameter to false, you should see the output for the DatePicker handler first, then the output for the document handler.

...

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

<div id="report"></div>

...

vardp = new WinJS.UI.DatePicker(document.getElementById("div"));

dp.addEventListener("change", handleChange, true);

document.addEventListener("change", handleChange, true);

functionhandleChange(ev) {

varelem = document.getElementById("report");

elem.innerHTML = elem.innerHTML + "<br> change event for " + this;

}

______________________________________

In the article above, we’ve gone over some of the basics of WinJS (the Windows Library for Javascript), and talked about using WinJS helper methods to create custom types and namespaces, as well as to utilize out-of-box and custom mixins to add functionality to your objects.

This tutorial is brought to you by the team at MSDN. To learn more about coding for Windows Store apps, please visit http://dev.windows.com

This article was reprinted with permission from Microsoft Corporation. This site does business with Microsoft Corporation.

IT Solutions Builder
TOP IT RESOURCES TO MOVE YOUR BUSINESS FORWARD

Which topic are you interested in?

Mobile

Security

Networks/IoT

Cloud

Data Storage

Applications

Development

IT Management

Other

What is your company size?

What is your job title?

What is your job function?

Loading Comments...

Web Development Newsletter Signup

Invalid email

You have successfuly registered to our newsletter.

HTML5 ebook

HTML5 is the new standard that is expected to take over the Web. New versions of browsers are already starting to support the advanced features. Learn why HTML5 is important and discover how to use start using it today.

Advertiser Disclosure:
Some of the products that appear on this site are from companies from which QuinStreet receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. QuinStreet does not include all companies or all types of products available in the marketplace.