Thursday, April 25, 2013

Windows 8 ListView Data Binding - Dynamically adding and removing items from a WinJS ListView

A common theme in your app may be the dynamic additions to a WinJS ListView. The ListView control, while HTMl/JavaScript based acts like you would expect a XAML List with dynamic binding to act. What I mean is that you can dynamically add and remove items and have them automatically appear. There are no tricks to make this happen, you just have to ensure you do it correctly. The binding steps are simply 1. Create a WinJS.Binding.List wrapper around your collection. 2. Specify a template and bind the above list to your ListView
Now let's look at two ways to bind data 
1. Using a typical JSON array
2. Using a defined object
DO ensure the item you are binding is a WinJS.Binding.List ie
var customerList = new WinJS.Binding.List(customers);

A word on closing tags

DO ensure that your elements have CLOSING TAGS.
I cannot stress this enough. You will bang your head on the table trying to debug your issue.
Mark my words - ensure your non-void elements have separate closing tags.

Example - DO
<div id='content'></div>

Example - DO NOT
<div id='content' />

Most elements in HTML5 need closing tags.

There are only about two 'self closing' tags and the 'void' tags (like img) simply ignore the closing slash, so it's not really required in the case of void tags anyways. If you want more details on that see:
  • Start Tags (see point 6)
  • Elements from the MathML namespace and the SVG namespace are the only ones that can use the self closing '/', see here
  • And if you really want to know the 16 void elements that don't need a closing tag they are: area, base, br, col, embed, hr, img, input, keygen, link, menuitem, meta, param, source, track, wbr defined Here


Ok, let's get to it!

Using a typical JSON array for binding

Here's your HTML
<div id="simpleBinding" data-win-control="WinJS.UI.ListView"></div>

<div id="moreBinding" class="bindingSample" data-win-control="WinJS.UI.ListView"></div>

<div id="simpleBindingTemplate" data-win-control="WinJS.Binding.Template">
    <h3 data-win-bind="innerText:name" />
    <span>Name :</span><span data-win-bind="textContent: name"></span>
    <img data-win-bind="src:imageUrl" />
</div>
And your JavaScript
//your data to bind
var people = [{ name: 'mary', birthday: '1/1/2010' }, 
              { name: 'fred', birthday: '1/1/2012' }];

//create a bindable list from the data
var simpleFriends = new WinJS.Binding.List(people);

//get the ref to your list view, note we call winControl to get 
//the 'functional' windows control from it to do cool things with
var simpleListView = document.getElementById('simpleBinding').winControl;

//get your div that is the template to render each item as
var simpleTemplate = document.getElementById('simpleBindingTemplate');
//can _could_ also set in the markup for this element where you declare your list
//
simpleListView.itemTemplate = simpleTemplate;

//and bind it!!
simpleListView.itemDataSource = simpleFriends.dataSource;

//add a new item. the binding update happens automatically
//Could use a Person object we defined
//simpleFriends.push(new Person({ name: "Dynamically added", birthday: "2/2/2002"}));

//or JSON
simpleFriends.push({ name: "Dynamically added", birthday: "2/2/2002"})

And now for using an Object for binding

The code is is almost exact except instead of creating an array we are creating a customer object that we can then 'new up'.
The HTML is the same block as above, and the JavaScript is as follows:
//Create a customer object. You can also do this via WinJS.Class.define as well 
//to create a 'class'. The syntax is very similar.
var Customer = WinJS.Binding.define({
    customerId: "",
    name: ""
});

var customers = [
    //note - if you add a field here that wasn't defined in the binding above it is just ignored and not bound to anything
    new Customer({ customerId: "1", name: "Mary Jones" }), 
    new Customer({ customerId: "2", name: "Sally Smith" }),
    new Customer({ customerId: "2", name: "Zadie Zebrazeus" })
];
            
var customerList = new WinJS.Binding.List(customers);
var moreBindingLv = document.getElementById('moreBinding').winControl;

//Assign our data and rendering template
moreBindingLv.itemDataSource = customerList.dataSource;
moreBindingLv.itemTemplate = simpleTemplate; //can also set in the markup for this element
            

customerList.push(new Customer({ customerId: "4", name: 'Fourth Awesome Person' }));
customerList.push(new Customer({ customerId: "5", name: 'Fifth Awesome Person' }));
            
//now delete item 5 (zero based)
customerList.splice(4, 1);
            

4 comments:

  1. Hi Adam,
    Thanks for your post. I am facing strange issue while updating the list. I have posted it in windows 8 forum. Please refer link below
    http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/45443196-57bc-4d3c-92fe-8dd25aacf432
    Can you please advise what can be the reason?

    ReplyDelete
    Replies
    1. There was a request there for more information, post a complete test case.

      Delete
  2. You actually have collected the main nuances of working with ListView WinJS. But everything comes with experience. I work in http://www.promwad.com/ and we have a large number of orders at the moment. And thanks to the staff and continuous training we work on the operational quality. So it is important to refresh our knowledge.

    ReplyDelete