I’ve been writing about this subject more thoroughly for the second edition of my book (view preview here), and thought to share the results here in two parts.

When WinJS.Binding.processAll encounters a data-win-bind attribute on an element, its main job is to take each <target property> : <source property> [] string and turn it into a real binding relationship. Assuming that the data source is observable, this basically means calling the source’s bind method with the source property name and some handler that will update the target property accordingly.
The purpose of the initializer function in this process is to define exactly what happens in that handler, that is, what happens to the target property in response to a source property update. In essence, an initializer provides the body of the handler given to the source’s bind (that is, each binding source is an object that has a bind method, typically brought in from the WinJS.Binding.mixin or observableMixin, which is done when you call WinJS.Binding.as or WinJS.Binding.define for a data source).

In a simple binding relationship, that code might simply copy the source value to the target, or might involve a converter function. It could also consolidate multiple source properties—you can really do anything you want here. The key thing to remember is that the initializer itself will be called once and only once for each binding relationship, but the code it provides, such as a converter function, will be called every time the source property changes.

Now if you don’t specify a custom initializer within data-win-bind, WinJS will always use a default, namely WinJS.Binding.defaultBind.  It simply sets up a binding relationship that copies the source property’s value straight over to the target property, as you’d expect. In short, the following two binding declarations have identical behavior:

data-win-bind=”innerText: name”
data-win-bind=”innerText: name defaultBind”

WinJS.Binding provides a number of other built-in initializers that can come in handy:

  • oneTime Performs a one-time copy of the source property to the target property without setting up any other binding relationship. This is necessary when the source is a WinRT object, as the proxy used for marshalling doesn’t supporting observability for one-way or two-way binding.
  • setAttribute and setAttributeOneTime Similar to defaultBind and oneTime but injects a call to the target element’s setAttribute method instead of just copying the source value to a target property. This is how you bind to DOM element attributes rather than object properties.
  • addClassOneTime (WinJS 2.0 only) Like setAttributeOneTime except that it interprets the source property as a class name and thus calls the target element’s classList.add method to apply that class. This is useful when working with binding templates.

Beyond these, we enter into the realm of custom initializers. The most common and simplest case is when you need to inject a converter into the binding relationship. All this takes on your part is to pass your conversion function to WinJS.Binding.converter, which returns the appropriate initializer (that’s also marked for declarative processing). For example, in the example below the function userTypeToColor is a simple data-conversion function, so we can create an initializer within the MyInitializers namespace as follows:

WinJS.Namespace.define(“MyInitializers”, {
//…
typeColorInitializer: WinJS.Binding.converter(userTypeToColor)
});

which we use in the HTML like so:

<span id=”loginName3″
data-win-bind=”innerText: name; style.color: userType MyInitializers.typeColorInitializer”>
</span>

Doing anything more requires that you implement the initializer function directly. We’ll pick up this subject in Part 2.


Comments are closed