Écriture/lecture/modification de fichiers dans un projet Universel app/UWP et cordova

Dans nos applications, nous avons pris le parti d’écrire nos fichiers en JSON. Nous avons donc conçu une abstraction (en WinJS, avec un système de promises) qui nous permet d’utiliser des méthodes claires et simples sur toutes les plateformes (WinRT/UWP ou Cordova (iOS/Android) )

Ce module « DataContainer » est disponible dans notre libraire WinJSContrib (Github)

Dans WinJSContrib.DataContainer, nous avons 4 fichiers qui exposent les mêmes méthodes avec des implémentations différentes :

  • read : lecture d’un élément
  • save : enregistrement d’un élément
  • remove : suppression d’un élément
  • list : liste des fichiers d’un container
  • child : création/accès container enfant

Dans une application WinRT/UWP nous allons naturellement utiliser la couche WinRT/UWP pour écrire/lire les fichiers. Pour cela il suffit d’inclure le fichier « winjscontrib.datacontainer.winrt.file.js »

Dans une application cordova IOS ou Android, nous avons plusieurs choix :

  • Utiliser une base de données : winjscontrib.datacontainer.cordova.database.js
  • Utiliser le système de fichiers avec le plugin file : « winjscontrib.datacontainer.cordova.file.js »
  • Utiliser le localStorage : « winjscontrib.datacontainer.localstorage.js » (utilisable en WinRT aussi)

Ensuite, il faut instancier un container parent et l’utiliser partout dans l’application.

Dans le JS des applications Windows 8/Phone il suffit d’instancier le container (dossier) parent :

MyApp.Data.container = new WinJSContrib.DataContainer.WinRTFilesContainer(undefined, { logger: WinJSContrib.Logger });

Et changer WinRTFilesContainer par notre choix (CordovaDatabaseContainer par exemple) pour l’application cordova en faisant attention de ne l’appeler qu’après l’enclenchement de l’évènement deviceready.

Et c’est tout, la magie s’opère à l’intérieur de notre librairie 🙂

Quelques exemples d’utilisation :

  • Pour lire un fichier :
  • Data.container.read("objKey").then(function (data) { }, function (error) { });
    
  • Supprimer un fichier :
  • Data.container.remove("objKey").then(function () { }, function (error) { });
    
  • Enregistrer un fichier :
  • Data.container.save("objKey",obj).then(function () { }, function (error) { });
    
  • Accès à un container enfant (sous dossier) avec la lecture d’un fichier fichier :
  • Data.container.child(folderid).read("subObjKey").then( function (subObjInFolderID) { }, function (error) { }));
    
  • Liste des fichiers dans un container :
  • Data.container.list().then(function (res) {}, function (error) { });
    

#UWPHTML – Building Windows 10 web applications

Many people still ignores it, but since Windows 8 (and 8.1 for Windows Phone), you can build Windows native applications using HTML and JavaScript. Yes you read it correctly NATIVE applications. Those applications does NOT run through a webview but with a native HTML/JavaScript application shell called « wwahost ». Those applications are now called « Windows web applications ».

Windows 10 introduced a few enhancements to Windows web apps. They run with a different security context and on Microsoft Edge engine. There is also something called « project Westminster ». More simply, Westminster is « hosted applications », or applications that runs with content hosted on the internet but still have access to Windows APIs. You could find more about hosted apps on our blog, or obviously on Microsoft’s blog.

Windows web apps are fully parts of the new concept of Universal Windows Platform applications. It means that you could make applications using HTML/JavaScript for Windows desktop and tablet, but also for Windows 10 mobile, Xbox, Windows IoT, and the soon to come Hololens.

This post is the first of a serie where we will talk about various aspects of Universal Windows web apps using HTML and JavaScript. We will illustrate the different topics with a real application called « Bring the popcorn », a remote controller for a Kodi or Xbmc media server.

This application is open source, and available in the Windows store. It uses WinJS and WinJSContrib to provide a fast and fluid experience, using the latest features of Edge and Chakra engine (or at least those made available in web apps…).

Hope you will enjoy this serie !

Writing Windows 10 App Services in JavaScript

What is an App Service ?

Windows 10 introduce a bunch of new ways for applications to communicate with each others. One way is to implement « App Services ». App Services are a request/response model where one app can call a service located within another app. App Services enable communication between apps, but also with the system. If you want to implement interactive scenarios with Cortana, you will have to implement an App Service to provide data to Cortana.

If you’re the kind of people who prefer code than blabla, you may head directly to the github repository with sample applications.

App Services use the same infrastructure as BackgroundTasks, and most of the logic and implementation details still applies. It means that when your service is called, you don’t have the whole application running, but only your service. It also means that your application don’t communicate directly with your App Service. For example, your application does not get notify when your service is called, or terminated.

In all resources I can found (Build session, Channel 9 videos, samples, …), App Services are implemented in C#. Those resources are really helpfull (especially this one on Channel 9), but if (like me) you are writing apps in HTML and JavaScript, it is likely that you prefer writing those services in JavaScript and share business code with the rest of your application. Porting C# resources to JavaScript is actually very easy. In this post, we will dive into implementing an App Service in Javascript, based on a C# sample from Microsoft Virtual Academy.

Show me some code !

In a Windows Web Application (Windows application written in HTML and JavaScript), a background task, therefore an App Service, should be thought of as a special Web Worker (no postMessage with it unfortunately). It’s a standalone JavaScript file that will get caught independently by the system.

The first step to implement your App Service is to create this file. As with web workers, you could use « importScripts » to reference any code you want to share between your app and the service. Be aware that, like with Web Workers, there is no « window » or « window.document » objects inside your background task or app service. The global context points to a completely different beast, and there is no DOM.

Inside your task or service, you will access to the current instance of the BackgroundTask object using WinRT APIs, and get a deferral on it to control the lifecycle of your service. As with background task, your service can also be canceled by the system if it needs to recover memory, or if battery is running low on the device. Your task instance provide a « cancel » event that will get caught is such cases.

A minimalistic background task/app service would look like this

var backgroundTaskInstance = Windows.UI.WebUI.WebUIBackgroundTaskInstance.current;
var triggerDetails = backgroundTaskInstance.triggerDetails;
var bgtaskDeferral = backgroundTaskInstance.getDeferral();

function endBgTask() {
    backgroundTaskInstance.succeeded = true;
    bgtaskDeferral.complete();
    bgtask.close();
}

backgroundTaskInstance.addEventListener("canceled", function onCanceled(cancelEventArg) {
    return endBgTask();
});

Now we must declare this file as an App Service. For that, we must add an extension to our application in its manifest, pointing to our javascript.

<Applications>
    <Application Id="App" StartPage="default.html">
        ...
        <Extensions>
            <uap:Extension Category="windows.appService" StartPage="js/appservice.js">
                <uap:AppService Name="MyJavascriptAppService"/>
            </uap:Extension>
        </Extensions>
    </Application>
</Applications>

As you can see, we provide the path to our JavaScript file, and we are giving a name (MyJavascriptAppService) to the App Service.

Now we must implement the service logic. To do that, we will check the trigger details on our background task, and register for a request event. When the event gets activated, we received an App Service request. This request will contains a message (with request arguments), and a sendResponseAsync method to reply to the caller. On both sides, the values in the request and in the response are provided with a ValueSet object.

//check that the app service called is the one defined in the manifest. You can host
//multiple AppServices with the same JavaScript files by adding multiple entries in the application manifest
if (triggerDetails && triggerDetails.name == 'MyJavascriptAppService') {
    triggerDetails.appServiceConnection.onrequestreceived = function (args) {
        if (args.detail && args.detail.length) {
            var appservicecall = args.detail[0];
            //request arguments are available in appservicecall.request.message
            var returnMessage = new Windows.Foundation.Collections.ValueSet();
            returnMessage.insert("Result", 42);
            appservicecall.request.sendResponseAsync(returnMessage)
        }
    }        
}

Calling your App Service

The app calling your service can be any app. If you want to restrict access, you will have to implement your own security mecanism. As you may have understood, the caller and the callee doesn’t have to be written in the same language. You can call a service written in C++ from a JavaScript app. All data are passing throught Windows APIs.

Calling the app service require some arguments, the caller should provide the package family name (PFN) of the target application, and the name of the App Service (as declared in the target’s app manifest). If you don’t know your PFN, you can get it through WinRT APIs by calling « Windows.ApplicationModel.Package.current.id.familyName » in your service application.

Using the PFN and service name, you will first get a connection to your App Service, and register to the « serviceclosed » event to be notified if your service terminate.

function getServiceConnection(){
    var connection = new Windows.ApplicationModel.AppService.AppServiceConnection();
    connection.appServiceName = "MyJavascriptAppService";
    connection.packageFamilyName = "...your PFN here...";

    return connection.openAsync().then(function(connectionStatus){
        if (connectionStatus == Windows.ApplicationModel.AppService.AppServiceConnectionStatus.success) {
            connection.onserviceclosed = serviceClosed;
            return connection;
        }
        else {
            return WinJS.Promise.wrapError({ message: 'service not available' });
        }
    });
}

Once you get a valid connection, you will be able to send requests to the service

function callService(){
    return getServiceConnection().then(function (connection) {
        var message = new Windows.Foundation.Collections.ValueSet();
        message.insert("Command", "CalcSum");
        message.insert("Value1", 8);
        message.insert("Value2", 42);

        return connection.sendMessageAsync(message).then(function (response) {
            var e = response;
            if (response.status === Windows.ApplicationModel.AppService.AppServiceResponseStatus.success) {
                document.getElementById('result').innerHTML = 'calculated ' + response.message.Result;
	                
                return response.message;
            }
        });
    });
}

And voilà ! you’re ready to go. A picture is worth a thousand words, so I put a sample with service and caller apps on github for you.

Debugging your service

If you grab the sample, you can see how easy it is to debug your service. If you configure the solution to run both caller and callee on debug, you can set breakpoints in your app service. If you don’t want to run the full service app, you could also edit the properties of the project hosting the service. In the debugging section, you could set « Launch Application » to false. In that case, when you run debug for both apps, you will only see the caller application starting, but your breakpoints in the app service will get called appropriately.

Porting Windows API calls from C# to JavaScript

Windows 10 is still in preview, and as of this writing, a lot of the samples available are written in C#.
The fact that samples are not available in JavaScript does not means that the feature is not available in JavaScript. The only things that may not be available is all topics about XAML controls, like the new InkCanvas, the RelativePanel, and so on. All code related to Windows APIs may be used in JavaScript.

Porting C# code to JavaScript is actually straightforward, especially if you are familiar with WinRT development. Windows APIs (aka WinRT) are projected in all available languages (C++, C#, and JavaScript), using each language paradigms. So, moving C# code to JavaScript is just about changing variable names to lowercase (ex « connection.SendMessageAsync() » => « connection.sendMessageAsync() »), or use the « on… » syntax for event. For example « connection.RequestReceived += someEventHandlerCallback » will convert to « connection.onrequestreceived += someEventHandlerCallback ».

As you can see, this is really easy…

Build 2015 – JavaScript frameworks in your apps and sites from WinJS and beyond

Cette session permet de voir les dernières évolutions apportées à WinJS et son utilisation dans les Windows web apps, à travers une petite application. Elle aborde ensuite l’utilisation des contrôles de WinJS dans les frameworks les plus « hot » du moment, en portant cette même application, avec Knockout, Angular, et React.
C’est un panoram interessant, bien que superficiel, des frameworks front-end du moment.

Resolving WinJS webcomponents attributes

Now that you know how to use WinJS as webcomponents, and how to declare your controls, we will talk about the mecanism for resolving attribute values.

Lets work with an example :

<win-listview id="recentItemsList" member 
	itemdatasource="list:ctrl:recentItemsPromise" 
	itemtemplate="select:#pictureItem" 
	iteminvoked="event:ctrl:recentListItemInvoked"></win-listview>

You could think of attribute resolution as

[what to do]:[where to look]:[string token]

If you look at the « itemdatasource » attribute, you could read it like this : get the « recentItemsPromise » property from parent control, and wrap it in a WinJS.Binding.List for the ListView.

In this example, « recentItemsPromise » is just a string, and « ctrl » and « list » are operators. The list operator is smart enougth to see that it received a promise, and await it to set value.

Operators are just functions referenced in the namespace WinJSContrib.Utils.ValueParsers. You could provide your own operators by adding them to this namespace.

When the attribute is resolved, you will endup with something equivalent to :

list(domelement, ctrl(domelement, "recentItemsPromise"));

As you can see, their is no complex parsing involved, it is very efficient, and enforce composition. You have no limit at the number of operators you can chain like this.

You could find the list and details about built-in operators in the API documentation.

registering your WinJS webcomponents

In the last episode, we had a glimpse of using WinJS controls with webcomponents syntax, thanks to WinJS Contrib. Let’s dig a little deeper and see how you could use your own controls with it.

On platforms with non native implementation of webcomponents, the WinJS Contrib module is attaching an observer on each page controls (and releasing it on when disposing the page). This observer uses MutationObserver to track changes in the DOM and automatically build the WinJS controls that you registered. It means that controls, not on a page (like controls in default.html) are not instantiated. In such case, you must call « WinJSContrib.UI.WebComponents.inspect(element) » just like you would have to call WinJS.UI.processAll with vanilla WinJS.

Registering a control is just about providing the name of the DOM element, and how to map DOM attributes to your control implementation. If you don’t want to use DOM element attribute, you could still use data-win-options, or use both.

Declaring a control is quite easy. If you look in « winjscontrib.ui.webcomponents.js », you will find the declarations for WinJS controls. Lets look at the declaration for the DatePicker :

	WinJSContrib.UI.WebComponents.register('win-datepicker', WinJS.UI.DatePicker, {
		properties: ['calendar', 'datePattern', 'disabled', 'maxYear', 'minYear', 
				'monthPattern', 'yearPattern', 'onchange', 'current'],
		events : ['change']
	});	

You must call WinJSContrib.UI.WebComponents.register to wrap your control. You must at least provide the name of the DOM element, and the constructor for your control. The third argument is an object containing the mapping for your control. Within this object, the items in « properties » indicate the name of the properties that you want to map as attribute on the element, and « events » indicate the name of the events you want to map.

« properties » and « events » are shortcuts to build a mapping. You could provide a raw map if you have to do fancy stuf. Lets imagine that the calendar attribute used on DOM element must map to something like _calendarBuilder.calendar in your control. In such case you could use :

	WinJSContrib.UI.WebComponents.register('win-datepicker', WinJS.UI.DatePicker, {
		properties: ['datePattern', 'disabled', 'maxYear', 'minYear', 
				'monthPattern', 'yearPattern', 'onchange', 'current'],
		events : ['change'],
		map: {
			"CALENDAR" : {
				attribute : "calendar",
				property : "_calendarBuilder.calendar",
				type : "property",
				resolve : true
			},
			"CHANGE" : {
				attribute : "change",
				property : "_calendarBuilder.changeevent",
				type : "event",
				resolve : true
			}
		}
	});	

This syntax is more verbose but you have total control over the mapping. Note that the mapping key should be uppercase.

Another scenario that may come in mind is how do I map a fragment/page to a webcomponent ?

This is a lesser known feature of WinJS but WinJS.UI.Pages.define actually returns the constructor for the page, with the exact constructor signature of common WinJS controls (first parameters provides containing DOM element, and second parameter for control options).

To map a page/fragment to a component, you just have to pass the constructor. If you look at the searchbar control in the sample application, you will find an example that looks like this :

var SearchBarCtor = WinJS.UI.Pages.define("/controls/searchbar/searchbar.html", {
	//control implementation not mentionned here for brievity
});

//for use as standard control with data-win-control
WinJS.Namespace.define('Flickity.UI', { SearchBar: SearchBarCtor });

if (WinJSContrib.UI.WebComponents) {
   	WinJSContrib.UI.WebComponents.register('flickity-searchbar', SearchBarCtor);
}

The last use case we will cover now is for controls containing controls. Sometimes you write a control that wraps one or more other controls. You can map those controls directly to DOM attributes by using their own registration. WinJS Contrib has a control that wrap a SemanticZoom and the two associated ListView for managing list with groupings. The declaration for this control use that pattern :

WinJSContrib.UI.WebComponents.register('mcn-semanticlistviews', WinJSContrib.UI.SemanticListViews, {
	properties: [],
	controls: {
		"listview": WinJS.UI.ListView,
		"zoomedOutListview": WinJS.UI.ListView,
		"semanticZoom": WinJS.UI.SemanticZoom
	},
	map: {
		"DEFAULTGROUPLIMIT": { attribute: 'defaultGroupLimit', property: '_dataManager.defaultGroupLimit', resolve: true },
		"GROUPKIND": { attribute: 'groupKind', property: '_dataManager.groupKind', resolve: true },
		"FIELD": { attribute: 'field', property: '_dataManager.field', resolve: true },
		"ITEMS": { attribute: 'items', property: '_dataManager.items', resolve: true },
	}
});

The mapping can also have a « controls » section, which is used as a map. The key is the prefix for the control, and the value is the constructor for the control. When you register a control, the webcomponents module is creating a mapping and attach it to the constructor. That’s why you have nothing more to pass to map child control. However, the controls you are using as child map should have been declared before declaring this one.

The control can then be declared like this :

<mcn-semanticlistviews id="semanticzoom"
	listview.itemtemplate="select:#listItemTemplate"
	listview.groupheadertemplate="select:#groupItemTemplate"
	zoomedoutlistview.itemtemplate="select:#semanticItemTemplate"
	defaultGroupLimit="12"
	groupKind="global:WinJSContrib.UI.DataSources.Grouping.byField"
	field="metadata.genre"
	items="global:moviesSample">				
</mcn-semanticlistviews>

Next time we will have a look at the resolution of properties and detail the various options you have.

Using WinJS controls as webcomponents

WinJS Contrib goal is to makes WinJS development faster, and simplify common tasks. Last time we saw that WinJS contrib enables using JavaScript classes to define your pages, enabling ECMAScript 6 or Typescript in your applications.

This time we will talk about something that could radically change the way you write your pages. As stated previously, WinJS Contrib override core page control. This new control has the benefit of providing an extensible page lifecycle.

The code snippets in this post are coming from the sample applications we built to illustrate WinJS Contrib features. The first is from a vanilla WinJS application, and the other is from the exact same application with WinJS Contrib and webcomponents.

With vanilla WinJS, you declare controls like this:

<div id="recentItemsList" 
    data-win-control="WinJS.UI.ListView" 
    data-win-options="{ 
        itemTemplate : select('#pictureItem') 
    }"></div>

The control model in WinJS is very effective but this syntax for declaring controls is a bit ugly. It’s verbose, and the parsing of options does not allow extensions. In all WinJS samples, the list is bound to data in the options using a static variable. Believe me, it is really a bad practice. In some templates, you will find the data bound with syntax like this « select(‘.pagecontrol’).winControl.myData ». Despite the fact that this syntax is also ugly, in any real world application, you have to link some of your controls property to something coming from a promise. It can be http call, data stored in files, local database, etc. You end up writing code for wiring data and controls.

enter webcomponents !

WebComponents is a new paradigm, currently under discussion by W3C, to declare components as custom DOM elements. You can get details on this by looking at webcomponents.org. As the time of this writing, Webcomponents have native implementation in Blink (engine used in Chrome and Opera) and partial support in Firefox. No support in IE or Spartan yet.

Webcomponents is really a very promising spec, and almost all modern front-end framework uses this syntax. Unfortunately, WinJS does not…

WinJS Contrib has a new module, that enables using controls with a webcomponents syntax like this :

<win-listview id="recentItemsList" member 
    itemdatasource="list:ctrl:recentItemsPromise" 
    itemtemplate="select:#pictureItem" 
    iteminvoked="event:ctrl:recentListItemInvoked"></win-listview>

Using this also allow many improvements on the syntax. As you can see, some of the code that resides in the controller with vanilla WinJS now moved to the declaration of the control. The resolution of control properties can be extended and use the same mecanism we described previously for providing arguments to other WinJS Contrib helpers.

We will deep dive into this mecanism in another post, but to give you a sneek peak, this mecanism use operators to resolve the property. If we look at the « itemdatasource », the string « list:ctrl:recentItemsPromise » could be read as : get the recentItemsPromise property from the containing control, and wrap the result in a WinJS.Binding.List datasource. WinJS Contrib has several operators and you could add your own.

To use webcomponents in your application, you just have to include « winjscontrib.core.js » and « winjscontrib.ui.webcomponents.js ». The module is defining the components for most WinJS controls. It maps control’s properties as attributes on the DOM element. We haven’t tested them all with this new syntax. We would be pleased to get any feedback from you if you encounter troubles with it, or if we missed some properties.

This module use core webcomponents on platform supporting it, and a polyfill for the others. The polyfill uses « MutationObserver ». It means it will work on IE11 and above, so you can use it in your Windows 8.1 and Windows Phone 8.1 applications, and obviously on Windows 10. We haven’t fully tested on Android and iOS yet but it’s the next step, because we use WinJS in many cross platform applications.

In the next posts, we will detail the resolution of properties, and the way you could declare your controls to use webcomponents syntax. In the meantime, go check the sample application, and feel free to send us feedback.

WinJS and ES6

It’s time for a new episode about WinJS and WinJS Contrib ! this time we will talk about using ECMAScript 6 with WinJS and more specifically about using JavaScript classes.

With WinJS pages, you use object literal to define your pages, something like :

WinJS.UI.Pages.define('/pages/home/home.html', {    
    processed: function(element, option){ 
    },
    ready : function(element, options){
    }
});

WinJS will build a constructor for the page and add the content of the object literal as a mixin on that constructor. When the page is invoked, the constructor is used to produce a new object that hold those methods on its prototype. What is great is that you could call WinJS.UI.Pages.define multiple time on the same page, using some external mixin. This model is very interesting because you could work in the best possible way for a developper : composition.

This programming model has no limit in terms of what you can do, however it has some drawbacks. First, a lot of developpers are not JavaScript gurus. Using OO languages along with JavaScript, they are not familiar or comfortable with the concept of mixins and this syntax looks like some esotheric thing. It’s also a different programming model than the business logic where you may enforce something more « object oriented ». I know « object oriented » is not in the « pure » JavaScript paradigm, but that’s where JavaScript is going with things like ES6 classes.

The other problem with this syntax is about the tooling. More often than not, intellisense goes nuts and does not provide you any help about a variable you created in another function, 5 lines of code above.

Last but not least, the object literal makes things like ECMAScript 6 classes, or Typescript a hell to work with WinJS. This is really odd because : 1 – Typescript is from Microsoft and it does not fit well with their own UI/front-end framework, and 2 – if you play with Windows 10 preview and dev tools, you may have noticed that, if you create an universal app in JavaScript, you can use ES6 in your application. It has not been officially announced yet but it looks like Windows 10 UAP in HTML and JavaScript uses some form of EdgeHTML (the Spartan engine). It means that you can use all the ES6/HTML/CSS goodness that comes along with it, as well as the performance benefits.

So, how could you use JavaScript / ES6 / Typescript classes with WinJS ? in fact it is quite simple. Last time we looked at the basic features of WinJS Contrib, and more specifically the fact that WinJS Contrib override WinJS page control. Once you put WinJS Contrib, you could call WinJS.UI.Pages.define with a constructor instead of an object literal.

class HomePage{
    ready(element, options){
    }
}
WinJS.UI.Pages.define('/pages/home/home.html', HomePage);

If you start playing with ES6 or Typescript, you may also use some of the other ES6 features. One that could help you improve readability and reduce code is arrow functions. Arrow functions are anonymous function with a syntax identical to lambdas in C#. In addition to syntactic sugar, the arrow functions does not change scope. If you use arrow function instead of functions, the « this » scope is preserved, and you avoid writing tons of ugly code like « that = this ».

To demonstrate those features, we made an ES6 version of the demo application using JavaScript classes. This version is still a Windows 8 version transpiled using Babel, but if you want to have a lot a fun, you could bring it to a Windows 10 UAP (it’s just copying files) and drop Babel, it will work just fine and it is a wonderful playground to experiment with new features of HTML/Javascript in the new rendering engine in Windows 10.

If you want a more direct look, you could check the « searchbar » control that we used to illustrate WinJS Contrib basics on the previous post.

WinJS Contrib Basics

Now that we set the stage for WinJS and WinJS Contrib, it’s time to dig into some code goodness.
In this episode, we will look at the fundamental of WinJS Contrib.

interactive elements

You have interactive elements in all apps. Weither it is with mouse or touch, it is good practice to provide visual feedback on interactions, otherwise the user feel trust in your application. WinJS Contrib has an abstraction over interactive element. Using it will provide an appropriate cursor with mouse, and a visual feedback with touch. It is as simple as :

WinJSContrib.UI.tap(domElement, callback, options);

the third argument is optional and allow you to specify such thing as « disableAnimation » to avoid the « pressed » effect with touch, or « lock » to add interactivity on elements in a scrollable are (like adding a button inside an item in a listview). The beauty is that « tap » is cross platform and will act as « fastclick » on Android and iOS.

When using it, a css class « tap » will be added on the element, and when element is pressed a « tapped » will be set as long as the element is pressed. You can use this to override the default animation.

In previous post, we explained that WinJS Contrib replaces the page implementation of WinJS. Our page control allow you to declare taps in your markup. You must simply add a « tap » attribute on an element, and as a value, you pass the name of the function on your page, like this :

<div class="button" tap="someFunctionOnMyPage"></div>

When called, your function will be bound to the page, it means that when the function is called, « this » refer to your page.

You could specify arguments to tap by adding a « tap-args » attribute. The value will be passed in the argument to the function on your page. The value could be a simple string, or use the resolution pipeline from WinJS Contrib. We will expand on this pipeline in another post, for now, just note that you can inject argument from a property or a function of your page.

<div class="button" tap="someFunctionOnMyPage" tap-args="ctrl:somePropertyOrFunctionOnMyPage"></div>

Another thing that is really common in all applications is to navigate after clicking a button. You can implement this as easily as tap with a « linkto » attribute. As a value, you will specify the url of the target page.

<div class="button" linkto="/pages/home/home.html"></div>

In case you want more, linkto can have arguments, just like tap. The arguments will be passed to the navigation

<div class="button" linkto="/pages/home/home.html" linktoargs="obj:{ index: 3}"></div>

interacting with DOM

When writing a WinJS page, you end up writing tons of DOM selector to get instances of the controls, or DOM element that you will interact with. Your page end up looking a bit ugly with things like this all around the place :

var listView = page.element.querySelector('#myListView').winControl;

If you are wandering why scoping selector to page, go have a look at some WinJS best practices.

WinJS Contrib page introduce a mecanism to map elements and controls as properties on your page by adding a « member » attribute on the node. You could leave it blank, and the name of the property will be the « id » on the node, or you could specify the name of the property.

<div class="button" member="btnClose"></div>

If the element has a control attached on it, the property will hold the control, otherwise it will be the DOM element :

<div member="listview" data-win-control="WinJS.UI.ListView"></div>

then you will use it magically in your page :

page.listview.itemDataSource = new WinJS.Binding.List().dataSource;

If you prefer having the declarations in your page, we still have some goodness for you. The page control has « q » and « qAll » functions for running querySelector and querySelectorAll from your page element, which is at least shorter than the full syntax. The « qAll » function is also kind enougth to map the result as an array, so you can use forEach on the result.

page.qAll('.button').forEach(function(buttonElement){
    //do something
});

preventing leaks

The first cause of memory leaks is unreleased event listeners having a closure on some global variable. To ensure releasing your listener without adding some (ugly) extra code to your page, WinJS Contrib provide an event tracker object. The page control holds an instance of it that you can use. You use this object to attach functions to event listeners, and when you dispose the tracker, it will dispose all attached events automatically. If you use the page instance, the page will take care of releasing the tracker.

instead of

ctrl.showBinded = ctrl.show.bind(ctrl);    		 
ctrl.searchInput.addEventListener('focus', ctrl.showBinded);
...
ctrl.searchInput.removeEventListener('focus', ctrl.showBinded);

you have :

ctrl.eventTracker.addEvent(ctrl.searchInput, 'focus', ctrl.show.bind(ctrl));    

does all this really help ?

Well, see for yourself by looking at the small sample application that we made. You have one version with WinJS only, and another with WinJS Contrib.

This application is for searching Flickr. If you look at the code for the search bar control and compare the pure WinJS and the WinJS Contrib version, you will see a real difference (it removed 45 lines of code on 154…)

Next time we will see other features enabled by the WinJS Contrib page