thoughts on coding

June 20, 2012

Template Selector control

Filed under: Javascript, Windows8, WWA — Frantisek @ 7:56 am

MvvmJS control: TemplateSelector

WinJS enables the developers to use declarative programming in UI layer. It fits very well with MVVM architectural style. The main idea is that UI (view which is HMTL part) can be managed by the javascript object ( ViewModel ). All of this works automatically thankfully to data-binding.

Example: lets have a HTML element wich is “bound” to ViewModel (JS object). Changes done in ViewModel can be reflected on HTML element, i.e. it can change a style, color, change a text inside, etc. Full example can be checked here

The idea can be extended a level higher. The idea is taken from WPF/Silverlight world, especially from Caliburn (as I worked with it for more than a year).

MvvmJS.UI.TemplateSelector control

The goal of this control is simple: selects a template for the databinding context object and then renders it with that template.

The common usage scenario is: let’s have ListView which displays messages and each message has a type. Each type contains different properties and is handled and rendered differently. Solution is simple.

Code behind part

    var elm = document.body;

    var list = new WinJS.Binding.List();

    list.push({ type: 'call', duration: 100 });
    list.push({ type: 'text', text: 'Hello world!' });
    list.push({ type: 'call', duration: 300 });
    list.push({ type: 'call', duration: 200 });
    list.push({ type: 'text', text: 'WinJS is cool!' });

    WinJS.UI.processAll(elm).then(function () {
        return WinJS.Binding.processAll(elm, { messages: list });
    });
    

The above code creates list of the messages and each message has a type (call, text). Message types have different properties. After filling the list we process all win controls within the document.body and then we run databinding process over it.

Rendering part

    <div id="messageTemplate" data-win-control="WinJS.Binding.Template">
        <div class="message" data-win-control="MvvmJS.UI.TemplateSelector" 
            data-win-bind="winControl.model:self MvvmJS.Binding.wbind"
            data-win-options="{ selector: {
		                            type: MvvmJS.UI.TemplateSelector.PropertySelector,
		                            property: 'type',
		                            pattern: '/default.html#{0}',
	                            } }">
        </div>
    </div>
    <div data-templateid="call" data-win-control="WinJS.Binding.Template">
        <div class="call">Call, duration <span data-win-bind="innerText:duration"></span>s</div>
    </div>

    <div data-templateid="text"class="message text" data-win-control="WinJS.Binding.Template">
        <div class="text">Text message: <span data-win-bind="innerText:text"></span></div>
    </div>

    <div id="listView"
        data-win-control="WinJS.UI.ListView"
        data-win-bind="winControl.itemDataSource:messages.dataSource"
         data-win-options="{ itemTemplate: messageTemplate }">
    </div>
    

There is a listview which gets the messages as an input. The template used for the rendering refers to a template with template selector control. Template selector control gets the message as the input (setting property model) and renders it. Template selector selects the template based on the property (setting selector option to PropertySelector class) “type” of the input object (in this case a message).

Templating

The templates are located in the file default.html and are identified by data-templateid attribute. Template selector uses template loading mechanism with caching capabilities. The templates are identified by “#”. For the above example, in case message is of ‘call’ type, then the pattern ‘/default.html#{0}’ will be replaced to ‘/default.html#call’ which identifies the template with data-templateid attribute ‘call’ in the file ‘/default.html’. The recommended approach is to store the templates in the separate file, i.e. templates.html.

The result

Just another example

Another common situation is just having a general “alert” dialog which gets an object as the input. Based on the object type it’s possible to choose appropriate template to render the message, i.e. exception, business messages, etc. In the traditional scenario it’s necessary to write Javascript code with ifs or switch/case and manualy inject HTML into UI.

Summary

The above mentioned problems are very common and they have very similar solution which I isolated into a control. The control is under development and there will be several enhancements added, i.e. animations. The complete example can be found on http://mvvmjs.codeplex.com/

Advertisements

June 10, 2012

Binding list and its projections

Filed under: Javascript, WWA — Frantisek @ 8:46 pm

Binding list and its projections

General introduction

WinJS.Binding.List class was introduced into WinJS stack for providing “observable arrays” – a combinaton of Array API and the observable functionality. There is a documentation about WinJS.Binding.List here so I’ll focus on one its specific feature – projections.

WinJS.Binding.List class provides methods to create a view over its data. This view is called projection and there are two default projections:

  1. sorted list projection: it’s created by calling method list.createSorted(sortingFn)
  2. filtered list projection: it’s created by calling method list.createFiltered(sortingFn)

The projections are fully observable which means:

  • when an underlying list changes then the projection gets notification and updates itself
  • when a projection changes itself, it notifies others listeners about it

In addition the projection supports creating projection over projection and still keeping the same API as the underlying list – it implements a decorator pattern. This can create an interesting and useful combinations.

WinJS.Binding.List is mainly used to produce a data source object which is a primary input for WinJS.UI.ListView control. The same applies for the projections, too. This creates very common, powerful combination in real-world application scenarios.

Filtered combined with sorted list projections example

In the following example there is a underlying list which contains strings. Then from the list there is created sorted projection which creates a sorted view over underlying data. Then there is created filtered projection which filters strings starting with ‘b’. The result test is following:

        it("filtered over sorted projections", function () {
            var list = new WinJS.Binding.List();
            var sorted = list.createSorted(function (l, r) {
                return l.v.localeCompare(r.v);
            });

            var filtered = sorted.createFiltered(function (x) { return x.v[0] === "b"; });

            list.push({ v: "a" });
            list.push({ v: "b55" });
            list.push({ v: "c" });

            var item = list.getAt(0);
            item.v = "b0";
            list.notifyMutated(0);
            list.push({ v: "b99" });
            list.push({ v: "b44" });

            expect(filtered.getAt(0).v).toBe("b0");
            expect(filtered.getAt(1).v).toBe("b44");
            expect(filtered.getAt(2).v).toBe("b55");
            expect(filtered.getAt(3).v).toBe("b99");

        });
    

Common usage scernarios

Metro applications are based on the idea: “less is more” which means displaying less information but in more productive/usable way. A typical example is that there is one and only one underlying list of data (i.e. sales items) and the application displays them once on “hub” (an initial screen displaying the last 10 sales sorted by time), then on another screen displaying a subset of data ordered appropriately (comming from categories displaying only last 10 sales filtered for a category), etc.

The main idea is to load and build the list once, processing the changes to the underlying list once and automatically propagating them into all consumers, e.g. UI controls, list projections, etc. This can have great impact on the performance (less CPU sycles) ~ battery, developers productivity and maintenance.

Few bugs in projections but it’s getting better

WinJS.Binding.List and its projectios were introduced just before Win8 Beta version and there were several issue which I reported to Win JS team with appropriate fixes but you can start using it today. Just download the code from MvvmJS and reference bindingListExtensions.js. The project also includes the unit tests so all the functionality is fully tested.

Summary

WinJS.Binding.List and its projections are very useful and you can be very productive with them. As I used them, I encountered few scenarios where I had to create my own List projections by deriving from base list projections. I’ll write about them in next days.

Unfortunatelly list projections are “internal classes” but have quite stable API. I hope, WinJS team makes them publicly visible in WinJS package. There are some tricks how to over-come this issue but it’s just exceptional and I use it until they will be public (I hope it will be in RTM or final release build).

June 4, 2012

Binding extension functions (Part IV)

Filed under: Javascript, WWA — Frantisek @ 10:43 pm

Binding extension functions

WinJS binding declaration offers binding customization via a custom binding method. There are several possibilities how to specify binding extension method.

A background info

The steps required for binding functions are:

  1. write a function meeting the following method signature:
    function (source, sourceProperty, dest, destProperty)
    

    The parameter names are self-explainable.

  2. make it publicly available from the global window object (example bellow exposes a function accessible as MvvmJS.Binding.localize)
  3. the binding function has to be marked “supported for processing” (it’s a requirement introduced by Win8 RC build). It can be done i.e. calling WinJS.Utilities.markSupportedForProcessing(fn)

Example

   WinJS.Namespace.define("MvvmJS.Binding", {
        localize: function (source, sourceProperty, dest, destProperty) {
            ......
        },
        .....
    });

    var markSupportedForProcessing = WinJS.Utilities.markSupportedForProcessing;
    Object.keys(MvvmJS.Binding).forEach(function (key) {
        markSupportedForProcessing(MvvmJS.Binding[key]);
    });

Extensions in action

Sample JS object

Let’s have the following Javascript class which will be used throug all samples.

    WinJS.Namespace.define("BindingExtensions.ViewModels", {
        SampleViewModel: MvvmJS.Class.define(function () {
            this.color = "red";
        }, {
            generateColor: function () {
                var colors = ['red', 'green', 'yellow'];
                var index = Math.ceil(Math.random() * colors.length-1);
                this.color = colors[index];
            }
        }, {
            color: {
                get : function () {
                    return this._color;
                },
                set : function (value) {
                    this._color = value !== null && value !== undefined && value.length === 0 ? "empty" : value;
                    this.colorRes = "color." + this._color;
                    this.richDescription = "This is rich multiline <BR> text. Selected color is <b>" + this._color + "</b>";
                    this.isGreen = value === "green";
                }
            },
            isGreen: null,
            colorRes: null,
            richDescription: null
            
        })
    });

In other words, there is a class SampleViewModel defined on namespace BindingExtensions.ViewModels. The class has for properties:

  • color: it’s accessible property (with get/set methods) which sets the rest properties based on sample dummy logic.
  • isGreen: it’s value property returning true in case color is ‘green’
  • colorRes: it’s value property containing a calculated resource key in form ‘color.{colorname}’.
  • richDescription: it’s value property and contains a dummy rich description with a color name.

Binding extension: localize

Usage:

<div class="value" data-win-bind="innerText:colorRes MvvmJS.Binding.localize"></div>

Explanation:
It reads the key (string) from colorRes property, use WinJS.Resources to translate it to user’s language and sets innerText of DIV element. It also rerun in case colorRes changes automaticaly out of the box.

Binding extension: style

Usage:

<div class="value" data-win-bind="backgroundColor:color MvvmJS.Binding.style">background color set to selected color</div>

Explanation:
It reads the color from the property and sets its value to backgroundColor on DIV’s style object. It handles color property changes automatically out of the box and rerun the binding.

Binding extension: urlStyle

Usage:

<div class="value" data-win-bind="backgroundImage:colorUri MvvmJS.Binding.urlStyle">background color set as background image</div>

Explanation:
It reads the colorUri from the property and sets its formatted value (form ‘url(value)’) to backgroundImage on DIV’s style object. It’s just a specific version of previous ‘style’ extension. Of course, it handles colorUri property changes automatically out of the box and rerun the binding.

Binding extension: toggleClass

Usage:

<div class="value" data-win-bind="WARNING:isGreen MvvmJS.Binding.toggleClass">text is capitalized in case the entered color is green</div>

Explanation:
It reads the boolean property isGreen from the data context object and it adds/remove (based on boolean property) the class WARNING on DIV’s class attribute. Of course, it handles property changes automatically out of the box and rerun the binding.

Binding extension: twoway

Usage:

<input type="text" class="value" data-win-bind="value:color MvvmJS.Binding.twoway"></input>

Explanation:
It activates two-way databinding between a property of the UI element and a property of the datacontext object. By default, the element’s properties are not observable. The only way to be notified about the property change is to handle an appropriate event depending on the UI control. MvvmJS comes with the two-way binding support for the following elements:

  • textbox: event ‘input’
  • checkbox: event ‘change’
  • more elements come later

In the above example, the text entered into the textbox (name of the color) is copied to property ‘color’ on the datacontext object and vice versa (from the object’s property to the textbox value).

Binding extension: unsafeHTML

Usage:

<div class="value" data-win-bind="innerHTML:richDescription MvvmJS.Binding.unsafeHTML"></div>

Explanation:
It reads the property richDescription from the data context object and it sets innerHTML of DIV. This operation (setting HTML property) is threaten as unsafe and throws security exception. If the content of the property is safe and it’s necessary to preserve the markup then it’s necessary to set innnerHTML through window.execUnsafeLocalFunction method. Of course, if a datacontext property changes, it automatically reruns the binding.

Binding extension: event

Usage:

<div class="button" data-win-bind="click:generateColor MvvmJS.Binding.event">click to generate color</div>

Explanation:
It binds onclick event raised by DIV element to the datacontext’s method generateColor. In addition ‘this’ object of event handler method generateColor is preserved (‘this’ is set to the datacontext object).

Summary

All binding extensions are included in the sample project BindingExtensions downloaded from MvvmJS codeplex project.


	

June 2, 2012

Observables and data-binding in action (Part III)

Filed under: Javascript, WWA — Tags: , , , — Frantisek @ 11:03 pm

Observables and their usage in binding

The typical scenario where observables’ features are leveraged is data-binding (binding the observable objects to html element – in other words model/viewmodel to view).

Declaration syntax

WinJS establish data-binding to UI in the following form:

<div data-win-bind="targetPropertyChain:sourcePropertyChain [customBindingFunction]" >

This was a declaration with the following meaning:

  • targetPropertyChain: declares a target of the databinding. It’s property name on the HTML element. Example: innerText. It supports also the chain of the properties, e.g. winControl.content.
  • sourcePropertyChain: declares a source of the databinding. It’s property name chain on an object (also called databinding context) whose data are used for binding. Example: address.street, name, etc.
  • customBindingFunction: it’s an optional parameter and declares a custom databinding function which replaces the default databinding function. There are several examples of it developed in MvvmJS. WinJS comes with two binding functions:
    1. default: it’s default oneway databinding function which binds a property from databinding context into a property on HTML element initialy and any time property on context object changes.
    2. onetime: it’s the function which bind the property from databinding context into element only once and only once.

Usage examples

<div data-win-bind="innerText:name" >

It’s the most simple binding use-case and declares binding from datacontext.name to targetElement.innerText.

<div data-win-bind="VISIBLE:isEmpty toggleClass" >

This defines the binding with the custom binding function defined as an extension in MvvmJS. The binding function toggleClass adds class VISIBLE to the element CSS class attribute in case datacontext.isEmpty is true.

<div data-win-bind="innerText:person.homeAddress.street" >

This defines binding street of the home address of the person accessible as a property on datacontext object to the innerText property on the target HTML element.

<div data-win-control="MvvmJS.UI.TemplateSelector" data-win-bind="winControl.content:person" >

First, it declares control MvvmJS.UI.TemplateSelector control (a custom WinJS UI control) over DIV. Then there is a databinding of datacontext.person to content property of winControl attribute set on the target DIV element. Note: it’s usual practice/pattern that UI control sets attribute winControl on the element to control instance.

Data-binding in action

That was just the first part of the story: declaration. Now, lets make the databinding alive.

WinJS introduces WinJS.Binding.processAll(root, dataContext, ..other parameters..) method which:

  1. searches for any element with data-win-bind attribute on the HTML element tree starting with root (optionaly skipping root) and
  2. then process the binding declarations.

WinJS.Binding.processAll method is usually called from JS page or fragment file.

Example

(function () {
    "use strict";

    WinJS.UI.Pages.define("/views/dummyView.html", {
        element: null,

        ready: function (element, options) {
            this.element = element;
            element.winControl = this;
            this.options = options;

            var vm = new MvvmJS.Samples.DummyVieModel();
            WinJS.Binding.processAll(element, vm);
        },
    });
}());

The example above is code-behind of the view DummyView which runs the binding processing in the ready event handler (raised when the page is rendered and ready to be used). In the ready event it instantiates DummyViewModel (please note a convention DummyView ~ DummyViewModel).

In case of an enterprise application it would be better to generalize the approach and define a base class with calling the binding process method from its ready method (this also brings MvvmJS).

Property chain subscriptions

There is one very usefull feature of WinJS databinding. WinJS databinding leverage observables and adds there property chain subscription of any property in sourcePropertyChain.

Let’s explain it on the example in BDD (behavior driven development) style:
Given: there is the following binding declaration

<div data-win-bind="innerText:person.address.street" >

When: person OR address OR street changes

Then: the binding is reprocessed and div’s innertext contains new value. This is very usefull feature in complex scenarios.

Comparing to manual approach

In case of manual approach it would be necessary to:

  1. initialy read the property and set the HTML element property with the value
  2. subscribe to any property chain change and handle the it with setting the new value

Manual approach implies more boilerplate and repetitive code which increase complexity of the result JS code.

In the next part we will look into custom binding method and extensions introduced in MvvmJS.

Blog at WordPress.com.