NetAdvantage for jQuery & Windows 8 METRO – a nice blend!

Alexander Todorov / Wednesday, October 19, 2011

Microsoft has recently announced Windows 8 and METRO – a very exciting part of the platform is the ability to use JavaScript, HTML and JavaScript to write native METRO applications. Microsoft has created the Windows Library for JavaScript (WinJS) that serves as the foundation for METRO applications written in HTML and JavaScript.

Having NetAdvantage for jQuery, a pure client-side stack for web development, it was very tempting to check how well it works in a METRO app.

Overview

This article will give an example of a custom WinJS component which wraps the Infragistics jQuery grid in order to deliver similar development experience to using other WinJS built-in controls – without any modifications at all to the grid’s JavaScript or CSS! I will also show how to create native Blend design-time support for this component, and how to bind to native MS Multi-touch events with JavaScript.

Creating a WinJS control for the Infragistics jQuery Grid

Listing 1 shows how the custom WinJS component is structured – basically I am using the WinJS base API in order to define a custom class, which can attach to any HTML element on the page. The XML comments are important, since Visual Studio IntelliSense and Blend support depend on them. As you can see, we are defining our custom control in the WinJS.UI namespace. In the constructor of the class, I am simply creating a Promise instance, and in its callback I am instantiating an Infragistics jQuery Grid widget on the passed element. The custom control definition allows the following usage from anywhere in the METRO WinWebApp:

   1: <div data-win-control="WinJS.UI.IgGridView" data-win-options="{virtualization:true}"></div>

Grid widget options and public API can be easily exposed as shown below (virtualization and dataBind()).

Listing 1 – WinJS jQuery Grid extension
   1: // igGrid WinJS extension
   2:  
   3: (function (WinJS) {
   4:  
   5: WinJS.Namespace.defineWithParent(WinJS, "UI", {
   6:  
   7: /// <summary locid="1">IgGridView Control</summary>
   8:  
   9: /// <name locid="2">IgGridView</name>
  10:  
  11: /// <htmlSnippet><![CDATA[<div data-win-control="WinJS.UI.IgGridView"></div>]]></htmlSnippet>
  12:  
  13: /// <event name="dataBound" locid="3">Raised when the grid has been data bound</event>
  14:  
  15: /// <resource type="javascript" src="/winjs/js/base.js" shared="true" />
  16:  
  17: /// <resource type="javascript" src="/winjs/js/ui.js" shared="true" />
  18:  
  19: /// <resource type="javascript" src="/winjs/js/controls.js" shared="true" />
  20:  
  21: /// <resource type="css" src="/winjs/css/ui-dark.css" shared="true" />
  22:  
  23: IgGridView: WinJS.Class.define(function (element, options) {
  24:  
  25: /// <summary locid="4">IgGridView control</summary>
  26:  
  27: /// <param name="element" type="HTMLElement" domElement="true" locid="5">
  28:  
  29: /// </param>
  30:  
  31: /// <param name="options" type="object" locid="6">
  32:  
  33: /// The set of options to be applied initially to the Infragistics Grid control.
  34:  
  35: /// </param>
  36:  
  37: /// <returns type="WinJS.UI.IgGridView" locid="7">A constructed IgGridView control.</returns>
  38:  
  39: this._element = element;
  40:  
  41: var promise = new WinJS.Promise(function () { $(element).igGrid(options); }, null);
  42:  
  43: WinJS.UI.setControl(element, this);
  44:  
  45: // set options and delegate to the jQuery widget 
  46:  
  47: WinJS.UI.setOptions(this, options);
  48:  
  49: },
  50:  
  51: {
  52:  
  53: // public properties
  54:  
  55: /// <field type="Boolean">
  56:  
  57: /// enables / disables virtualization
  58:  
  59: /// </field>
  60:  
  61: virtualization: {
  62:  
  63: get: function () {
  64:  
  65: return this._virtualization;
  66:  
  67: },
  68:  
  69: set: function (value) {
  70:  
  71: this._virtualization = value;
  72:  
  73: }
  74:  
  75: }
  76:  
  77: },
  78:  
  79: { // public methods
  80:  
  81: dataBind: function () {
  82:  
  83: this._grid.dataBind();
  84:  
  85: }
  86:  
  87: })
  88:  
  89: }) (this, WinJS);
  90:  
  91: }) (WinJS);

Listing 2 shows the required script references that need to be put on the page. It’s important that we include a call to WinJS.UI.processAll() after all DOM content has been loaded, to ensure our custom control is properly initialized.

Listing 2 Required Script and CSS references

 

   1: <link rel="stylesheet" href="/winjs/css/ui-dark.css" />
   2:  
   3: <script type="text/javascript" src="DataSource.js"></script>
   4:  
   5: <link type="text/css" href="./css/ig.ui.min.css" rel="stylesheet" />
   6:  
   7: <!--
   8:  
   9: <link type="text/css" href="./css/jquery.ui.custom.css" rel="stylesheet"
  10:  
  11: -->
  12:  
  13: <script src="/js/default.js"></script>
  14:  
  15: <script type="text/javascript" src="/js/jquery.min.js"></script>
  16:  
  17: <script type="text/javascript" src="/js/jquery-ui-1.8.16.custom.min.js"></script>
  18:  
  19: <script type="text/javascript" src="./js/ig.ui.min.js"></script>
  20:  
  21: <script src="/winjs/js/base.js"></script>
  22:  
  23: <script src="/winjs/js/ui.js"></script>
  24:  
  25: <script src="/winjs/js/binding.js"></script>
  26:  
  27: <script src="/winjs/js/controls.js"></script>
  28:  
  29: <script src="/winjs/js/animations.js"></script>
  30:  
  31: <script src="/winjs/js/uicollections.js"></script>
  32:  
  33: <script src="/winjs/js/wwaapp.js"></script>
  34:  
  35: <script src="/winjs/js/grid.js"></script>
  36:  
  37: <!-- WinWebApp1 references -->
  38:  
  39: <link rel="stylesheet" href="/css/default.css" />
  40:  
  41: <script type="text/javascript">
  42:  
  43: (function () {
  44:  
  45: document.addEventListener("DOMContentLoaded", function (e) {
  46:  
  47: WinJS.UI.processAll();
  48:  
  49: });
  50:  
  51: })();
  52:  
  53: </script>
  54:  

All Infragistics jQuery widgets have very nice separation between layout-related CSS and visual (colors, etc.) CSS. Therefore, in order to prove this we can simple comment the reference to jquery.ui.custom.css which defines the colors, the borders, and so on – and see what happens. Luckily enough, most important METRO styles are directly picked up from METRO’s themes – ui-dark.css / ui-light.css. This is the end result after running the application:

One great thing about METRO and WinJS is the way it handles scrolling containers. There is absolutely no need to write special code to detect touch events that are on specific element, in order to prevent the whole page from scrolling. METRO nicely handles that, and as you can see, swiping with fingers on the grid element, actually scrolls the grid and not the whole METRO application window.

Expression Blend Design-time Support

A very important part of any platform is the ability to provide design time experience to its developers. Unfortunately this has been a somehow gray area for most of the client-side web development frameworks (as opposed to ASP.NET’s rich design-time support), and JavaScript and HTML haven’t been very design-time friendly in general… up to now. The Blend 5 version Microsoft is introduce with Windows 8 and Visual Studio 11, has full support for components developed with WinJS. I will show you this by adding custom design time experience to the control we have just developed.

Blend utilizes the OpenAjax format (www.openAjax.org) in order to describe the Control structure, such that Blend itself can pick it up and add it to its Assets window. This automatically implies drag and drop support, property window, data type support, etc. For example if we have a Boolean property, Blend will automatically render a checkbox for it, instead of an input box.

The following links give an in-depth overview of the structure of the XMLs that describe the control:

http://www.openajax.org/member/wiki/OpenAjax_Metadata_1.0_Specification_Widget_Metadata

http://www.openajax.org/member/wiki/OpenAjax_Metadata_1.0_Specification_API_Metadata

Since WinJS advocates a markup-driven approach to application development, this is the generated code after we drag and drop a component from Blend’s Assets window and drop it on the application viewport, and configure some options on it:

   1: <div data-win-control="WinJS.UI.IgGridView" id="grid1" data-win-options="{dataSource: namedData, height: 400, width: 600, features: [{name: 'Sorting', type: 'local'}]}" ></div>
   2:  
   3: <div data-win-control="WinJS.UI.IgGridView" data-win-options="{virtualization:true}"></div>

The below two files described in Listing 2 and Listing 3 are the minimum required assets in order to have design-time support in Blend. They should be placed in the following folder:

C:\Program Files\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\Microsoft.WinJS\0.5\js\metadata

The first file defines the API of the control - its properties, events, methods, etc. The second XML describes the widget as a Mashup component, as defined by OpenAjax – that is, the widget metadata, including script dependencies, etc.

Listing 2 - grid_api_oam.xml
   1: <?xml version="1.0" encoding="utf-8"?>
   2:  
   3: <api version="1.0" spec="1.0" xmlns="http://openajax.org/metadata">
   4:  
   5: <author name="Microsoft Corporation" />
   6:  
   7: <class name="WinJS.UI.IgGridView">
   8:  
   9: <properties>
  10:  
  11: <property name="virtualization" required="false">
  12:  
  13: <description locid="1" type="text/plain">enables / disables virtualization in the Infragistics grid </description>
  14:  
  15: </property>
  16:  
  17: </properties>
  18:  
  19: <events>
  20:  
  21: <event name="dataBinding" p4:bubbles="true" xmlns:p4="http://www.microsoft.com/schemas/Corsica">
  22:  
  23: <description locid="2" type="text/plain">Raised before the grid is about to data bind</description>
  24:  
  25: </event>
  26:  
  27: </events>
  28:  
  29: <methods>
  30:  
  31: <method name="dataBind">
  32:  
  33: <description locid="2" type="text/plain">DataBinds the Infragistics grid</description>
  34:  
  35: <returnType datatype="Boolean">
  36:  
  37: <description locid="4" type="text/plain">test </description>
  38:  
  39: </returnType>
  40:  
  41: </method>
  42:  
  43: </methods>
  44:  
  45: </class>
  46:  
  47: </api>
  48:  
  49: Listing 3 - grid_winjs.ui.iggridview_oam.xml
  50: <?xml version="1.0" encoding="utf-8"?>
  51:  
  52: <widget version="1.0" spec="1.0" id="ms-wwa://Microsoft.WinJS/0.5/js/controls/WinJS.UI.IgGridView" name="WinJS.UI.IgGridView" xmlns="http://openajax.org/metadata">
  53:  
  54: <author name="Infragistics Corporation" />
  55:  
  56: <description locid="24" type="text/plain">Infragistics jQuery Grid control</description>
  57:  
  58: <icons />
  59:  
  60: <properties> <property name="virtualization" datatype="Boolean" isInteger="false" required="false">
  61:  
  62: <description locid="42" type="text/plain"> enables disables virtualization</description>
  63:  
  64: </property>
  65:  
  66: </properties>
  67:  
  68: <content><![CDATA[<div data-win-control="WinJS.UI.IgGridView"></div>]]></content>
  69:  
  70: <requires>
  71:  
  72: </requires>
  73:  
  74: <parts xmlns="http://www.microsoft.com/schemas/Blend/Corsica"> </parts><locale messages="controls_loc_oam.xml" />
  75:  
  76: </widget>
  77:  

The final result – you can check those screenshots out … pretty cool for a mix of HTML, CSS and JavaScript!

Touch Events – Stay Tuned

WinJS defines support for custom multi-touch events: MSPointerDown, MSPointerMove, etc. Unlike standard (cross-) Browser events, those are specific Microsoft events with custom event argument classes. The cool thing is that if we bind to those events, they are fired both in a Desktop (not touch) environment, as well as in a multi-touch environment (phone, tablet).

I have done a very basic experiment, binding those events to the Infragistics jQuery Grid’s element – which is a HTML data TABLE, and logging some of the output. Using a Win Slate tablet, and tapping, swiping and pinching on the grid’s viewport, you can see those events are fired in a pretty predictable way.

Add this to the custom control extension:

   1: PT_TOUCH = 2; // indicates a touch event
   2:  
   3: this._events();
Listing 4 – Binding to Multi Touch Events
   1: _events: function () {
   2:  
   3: var that = this;
   4:  
   5: function gridHandler(eventName) {
   6:  
   7: return {
   8:  
   9: name: eventName,
  10:  
  11: lowerCaseName: eventName.toLowerCase(),
  12:  
  13: handler: function (event) {
  14:  
  15: var fn = that["_on" + eventName];
  16:  
  17: if (fn) {
  18:  
  19: fn.apply(that, [event]);
  20:  
  21: }
  22:  
  23: }
  24:  
  25: };
  26:  
  27: }
  28:  
  29: var eventsRegisteredInLowerCase = [
  30:  
  31: gridHandler("MouseDown")
  32:  
  33: ];
  34:  
  35: var events = [
  36:  
  37: gridHandler("MSPointerDown"),
  38:  
  39: gridHandler("MSPointerMove"),
  40:  
  41: gridHandler("MSPointerUp"),
  42:  
  43: gridHandler("MSPointerOut")
  44:  
  45: ];
  46:  
  47: var i;
  48:  
  49: for (i = 0; i < eventsRegisteredInLowerCase.length; ++i) {
  50:  
  51: this._element.addEventListener(eventsRegisteredInLowerCase[i].lowerCaseName, eventsRegisteredInLowerCase[i].handler, false);
  52:  
  53: }
  54:  
  55: for (i = 0; i < events.length; ++i) {
  56:  
  57: this._element.addEventListener(events[i].name, events[i].handler, false);
  58:  
  59: }
  60:  
  61: },
  62:  
  63: _MouseDown: function (eventObject) {
  64:  
  65: $("#log").text($("#log").text() + " MouseDown");
  66:  
  67: },
  68:  
  69: _onMSPointerMove: function (eventObject) {
  70:  
  71: if (eventObject.pointerType === PT_TOUCH) {
  72:  
  73: $("#log").text($("#log").text() + " MSPointerMove");
  74:  
  75: } else {
  76:  
  77: // $("#log").text($("#log").text() + " " + eventObject.pointerType);
  78:  
  79: }
  80:  
  81: }
  82:  
Figuire 5 – The Infragistics jQuery Grid in action in a native METRO application running on a WinSlate tablet

Summary

In this blog post, I have described how to create a custom WinJS METRO component, by wrapping the Infragistics jQuery Grid component and expose its API using the Windows Library for JavaScript conventions. I have also described how design-time support can be added for Blend, and how touch events can be attached to. Being completely client-side, modular and extensible, the Infragistics jQuery Grid proves to be a very nice match for anyone looking to build feature-rich data-driven METRO applications.

WinWebApp1.zip