How to bind a complex object (HTML)
[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]
In many cases you want your app to bind to complex objects, in particular objects that manage processes that are not controlled by the app's UI. This topic shows how to write an app that displays data from an object that contains a name and a color, which is basically the same as the Quickstart: binding data and styles. In this case the object manages the change process itself, instead of responding to a button that triggers the change.
Prerequisites
- Working through the topic Quickstart: Binding data and styles to HTML elements might help you to complete the steps in this how-to topic.
Instructions
Step 1: Setting up a project to use binding
Create a blank Windows Runtime app using JavaScript and name it ObjectBinding.
In default.html, add a DIV element for the binding and give it an ID of "objectBinding", an inner text of Welcome, and a SPAN element that has an ID of "bindableSpan", as shown here.
<body> <div id="objectBinding"> Welcome <span id="bindableSpan"></span> </div> </body>
Step 2: Setting up a complex object
Define a
Person
object that has name and color fields, an array of names, an array of color names, and a private method to provide a random index for the array. For the definition of this object, you can use the WinJS.Class.define method. Add this code inside the immediately-invoked anonymous function in default.js.(function () { "use strict"; // Other app code ... var Person = WinJS.Class.define( function() { this.name = "Harry"; this.color = "blue"; this.timeout = null; }, { _nameArray: ["Sally", "Jack", "Hal", "Heather", "Fred", "Paula", "Rick", "Megan", "Ann", "Sam"], _colorArray: ["lime", "lavender", "yellow", "orange", "pink", "greenyellow", "white", "lightblue", "lightgreen", "lightyellow"], _newName: function () { this.name = this._nameArray[this._randomizeValue(this._nameArray.length)]; this.color = this._colorArray[this._randomizeValue(this._colorArray.length)]; }, _randomizeValue: function (max) { return Math.floor(Math.random() * 1000) % max); } }); })();
Now add to the
Person
definition (the second argument passed to WinJS.Class.define) two public methods that start and stop a process that changes the name and color fields every 500 milliseconds. The complete call to WinJS.Class.define is shown below.(function () { "use strict"; // Other app code ... var Person = WinJS.Class.define( function() { this.name = "Harry"; this.color = "blue"; this.timeout = null; }, { _nameArray: ["Sally", "Jack", "Hal", "Heather", "Fred", "Paula", "Rick", "Megan", "Ann", "Sam"], _colorArray: ["lime", "lavender", "yellow", "orange", "pink", "greenyellow", "white", "lightblue", "lightgreen", "lightyellow"], _newName: function () { this.name = this._nameArray[this._randomizeValue(this._nameArray.length)]; this.color = this._colorArray[this._randomizeValue(this._colorArray.length)]; }, _randomizeValue: function (max) { return Math.floor(Math.random() * 1000) % max); }, // Starts the process that changes the name. start: function () { var that = this; if (this.timeout === null) { this.timeout = setInterval(function () { that._newName(); }, 500); } }, // Stops the process that changes the name. stop: function () { if (this.timeout !== null) { clearInterval(this.timeout); this.timeout = null; } } }); })();
Step 3: Binding the object to the HTML
Right now the Person object is not observable; that is, it does not provide notifications when it changes. We can make it observable by mixing the Person object with the correct binding functionality. The WinJS.Class.mix function adds to the Person object the functionality of the WinJS.Binding.mixin object, which includes a bind method, and the functionality of the WinJS.Binding.expandProperties function, which creates properties on the object for binding. Call WinJS.Class.mix after the
Person
object definition. (You need to define the Person class before you can mix anything with it.)WinJS.Class.mix(Person, WinJS.Binding.mixin, WinJS.Binding.expandProperties({name: "", color: ""}) );
You also need to call _initObservable inside the
Person
constructor to set up the _backingData property. Change thePerson
constructor as follows:... function () { this._initObservable(); this.name = "Harry"; this.color = "blue"; this.timeout = null; } ...
After you have instantiated a
Person
object, you can bind it to the two properties. The bind method takes two parameters: the name of the property or field that is to be bound, and a function that specifies how it is to be bound. This function has two parameters: the new value and the old value. Because bind is an instance method, for now we'll just instantiate aPerson
and call bind on its name and color fields. Add the following code inside the app.onactivated event handler in default.js.app.onactivated = function (args) { // Other activation code ... var myPerson = new Person(); myPerson.bind("name", onNameChange); myPerson.bind("color", onColorChange); function onNameChange (newValue) { var span = document.getElementById("bindableSpan"); span.innerText = newValue; } function onColorChange (newValue) { var span = document.getElementById("bindableSpan"); span.style.color = newValue; } }
Warning Do not attempt to bind data to the ID of an HTML element.
To enable the change events to occur, you must change the
Person._newName
function._newName: function () { this["name"] = this._nameArray[this._randomizeValue()]; this['color"] = this._colorArray[this._randomizeValue()]; }
You can test the binding by calling the
Person.start
method.myPerson.start();
When you build and run the app, you should see this:
Welcome, Harry
The name and the color of the name should change continuously.