Corrado's Blog 2.0

Online thoughts of a technology funatic

Two-way binding in WinJS

As many of you who couldn’t attend Build 2012 I’m watching recorded sessions posted on Channel 9.

I really enjoyed the Deep Dive into WinJS session and the trick to solve one of the big missings of WinJS databinding: the lack of Two-way support.

Let’s start with a simple default.html page:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>TwoWayBinding</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <!-- TwoWayBinding references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
    <style>
        input[type=text]
        {
            width: 300px;
            height: 50px;
            margin-left: 10px;
        }
        .host {
            margin-top: 50px;
            margin-left: 50px;
        }
    </style>
</head>
<body>
    <div class="host">
        <span class="win-type-x-large">Enter Value</span>
        <input type="text" data-win-bind="value: name" />
    </div>
</body>
</html>

Nothing special here, just a textBox bound to a “name” property.

Let’s create the source data inside default.js file, below only onactivated function is listed for brevity since the rest is exactly the same code generated by Visual Studio template:

app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {

            WinJS.Namespace.define("Data", {
                Person: {
                    name: "fabio"
                }
            });

            var src = WinJS.Binding.as(Data.Person);
            WinJS.Binding.processAll(null, src);
            src.bind("name", function (newValue) {
                console.log("Value is " + newValue);
            });

            args.setPromise(WinJS.UI.processAll());
        }
    };

As you see I created a Person class inside “Data” namespace, made it observable, and added tracking for “name” property updates using bind function.

Running the code, you’ll get, as expected,  a textbox filled with initial name “fabio”:

image

If we now type something inside textbox, you’ll see that no value change is tracked since, by default, WinJS binding is one-way only.

We all know how valuable is having two-way binding,  especially if you are a MVVM/KnockoutJS fan.

Luckily it is quite easy to achieve it, at least in its simplest form thanks to Binding Initializers that is a function that is invoked when binding is created, usually the invoked function is WinJS.Binding.defaultBind that creates the one-way binding.

Binding Initializers give you access to both source and target objects and their properties, this allow us to subscribe to target element’s events and push data to source object.

Here’s initializer definition:

WinJS.Namespace.define("Binding.Mode", {
                twoway: WinJS.Binding.initializer(function (source, sourceProps, dest, destProps) {
                    WinJS.Binding.defaultBind(source, sourceProps, dest, destProps);
                    dest.onchange = function () {
                        var d = dest[destProps[0]];
                        var s = source[sourceProps[0]];
                        if (s !== d) source[sourceProps[0]] = d;
                    }
                })
            });

Initializer is defined using WinJS.Binding.initializer object and passing a function that receives binding properties, inside the function we use WinJS.Binding.defaultBind to create a standard one-way binding then we subscribe target (textbox) onchange event and when it triggers we update source object.

Once defined, all we need is to apply the initializer to binding this way:

<input type="text" data-win-bind="value: name Binding.Mode.twoway" />

Running the app and typing something inside textbox, will now result in new value printed inside console window, confirming that source has been updated

image

Technorati Tags: ,

3 Responses to “Two-way binding in WinJS”

  1. Chau ! Thx a lot for this good explained article !

    Comment by 熊熊人 — 21/08/2013 @ 15:13

  2. Am I missing something? I’ve implemented this method, and while it persists changes to the input field back to the source, it doesn’t update the input field if the source property is changed by code. As it is now, it’s more like “oneway to source”.

    Comment by Tom Lint — 25/11/2014 @ 10:27

  3. Thank you SO MUCH!!!

    Comment by Alexander — 03/12/2014 @ 15:43

RSS feed for comments on this post. TrackBack URL

Leave a Response