2012年5月28日

[Windows 8]DataBinding–dynamic binding

I want to have my metro app automatically update data source when user changes data via screen. To archive this, I need to dynamically bind data to controls.

///<reference path="//Microsoft.WinJS.0.6/js/base.js"/>
///<reference path="//Microsoft.WinJS.0.6/js/ui.js"/>
(function () {
"use strict";
//As we want the "array" variable to be updated to control,
//for some reason, we MUST declare these "array" variables with type
//WinJS.Binding.List and outside the "WinJS.Binding.as"
var observerableStores = new WinJS.Binding.List();
var observerableItems = new WinJS.Binding.List();
WinJS.Namespace.define("ViewModel", {

DynamicData: WinJS.Binding.as(
{
myName: null,
getStores: function () {
return observerableStores;
},
addStore: function (s) {
observerableStores.push(s);
},
getItems: function () {
return observerableItems;
},
addItem: function (n, q, s) {
observerableItems.push({
item: n,
quantity: q,
store: s
});
}
}
)
});
//add some data
ViewModel.DynamicData.homeZipCode = "NY 10118_D";
ViewModel.DynamicData.addStore("Store1_D");
ViewModel.DynamicData.addStore("Store2_D");
ViewModel.DynamicData.addStore("Store3_D");
ViewModel.DynamicData.addStore("Store4_D");
ViewModel.DynamicData.addStore("Store5_D");

ViewModel.DynamicData.addItem("Mac Air 1_D", 5, "Store1_D");
ViewModel.DynamicData.addItem("Mac Air 2_D", 5, "Store1_D");
ViewModel.DynamicData.addItem("Mac Air 3_D", 5, "Store1_D");
ViewModel.DynamicData.addItem("Mac Air 4_D", 5, "Store3_D");
ViewModel.DynamicData.addItem("Mac Air 5_D", 5, "Store5_D");
}
)();


To dynamically reflect changes made on data source to UI, we need to invoke WinJS.Binding.as() function to create observable variables, moreover, as WinJS.Binding.as() only makes primitive typed object as observable, such as int, float…etc. so we need to declare our array as WinJS.Binding.List type to make them observable.



And note, for some tricky restrictions, we need to declare WinJS.Binding.JS variables outside of WinJS.Binding.as() as embedded codes indicate.



Now back to our html code.



<div class="win-type-x-large">Zip code is:
<span data-win-bind="innerText:DynamicData.myName"></span>
</div>
<div class="win-type-x-large">
<label for="newmyName">Enter myName:</label>
<input id="newmyName" data-win-bind="value:DynamicData.myName" />
<button id="newmyNameButton">Update myName</button>
</div>
<div class="win-type-x-large">
Last item is : <span id="lastItem"></span>
</div>
<div class="win-type-x-large">
<button id="addItem">Add Item</button>
<button id="removeItem">Remove Item</button>
</div>
</div>


To specific data binding, I use css class “data-win-bind” with its value in this format “[attribute: dataItem]”, for example data-win-bind=”innerText: DynamicData.myName”



Now to the codes



// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
"use strict";

var app = WinJS.Application;

app.onactivated = function (eventObject) {
if (eventObject.detail.kind ===
Windows.ApplicationModel.Activation.ActivationKind.launch) {
if (eventObject.detail.previousExecutionState
!== Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
initialSetup(eventObject);
} else {

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

app.oncheckpoint = function (eventObject) {

};

app.start();

function initialSetup(e) {
//tells WinJS to process Data Binding
WinJS.Binding.processAll(document.body, ViewModel);
document.body.querySelector("#newmyNameButton").addEventListener(
"click",
function (e) {
ViewModel.UserData.homeZipCode =
WinJS.Utilities.query("#newmyName")[0].value;
});
//when click on Add/Remove button, add/pop a item to/from the list
WinJS.Utilities.query("button").listen("click", function (e) {
if (this.id == "addItem") {
ViewModel.DynamicData.addItem("Ice cream", 2, "Vanilla");
} else if (this.id == "removeItem") {
ViewModel.DynamicData.getItems().pop();
}
});
//update displayed value
var setDynamicValue = function () {
var list = ViewModel.DynamicData.getItems();
if (document.getElementById("lastItem") != null && document.getElementById("lastItem") != "undefined")
if (list != null && list != "undefined" && list.length > 0)
document.getElementById("lastItem").innerText = list.getAt(list.length - 1).item;
};
//bind event handlers to list items
var events = ["itemchanged", "iteminserted", "itemremoved", "itemmoved"];
events.forEach(function (t) {
ViewModel.DynamicData.getItems().addEventListener(t, setDynamicValue);
});

setDynamicValue();
}

})();



Run the app, and change “myName” in the textbox, click “Update myName”, and the new name will be updated automatically onto the screen.

沒有留言:

About Me