LA.NET [EN]

Oct 29

DataViews, DataViews and more DataViews: DataViews everywhere!

Posted in Javascript MS AJAX      Comments Off on DataViews, DataViews and more DataViews: DataViews everywhere!

Ok, I think this title might have caught your attention! (at least, that’s what I’m hopping for!). This post is a direct consequence of another discussion with a friend regarding the use of the DataView control. He told me something like this: “well, DataViews are cool…can’t deny it…but it’s only for listing items and that means it’s only usable for grids…”

Aha! That is not correct. And to show him that he was wrong, we’ve settled in a challenge (not as interesting as top gear’s challenges, but still…). After some discussion, we’ve settle in simple scenario: an edit form for a complex JavaScript object. Here’s the UI:

complexform

The print button you see is there to give feedback on the values of the properties of the person object. And here’s the JavaScript for the objects used in the sample:

var contactTypes = [
      { id: 1, description: "phone" },
      { id: 2, description: "email"}];
var person = {
  name: "luis",
  address: "some place",
  contacts: [
    { contact: "123123123",type: contactTypes[0]},{ contact: "labreu@somewhere.pt", type: contactTypes[1]}
  ]
};

As you can see, we’ve got a collection of literal contact types objects which are used for identifying the types of each of the contacts saved in the person object.  To solve this problem, I’ve ended up defining three DataView controls:

  • one for the top form;
  • another for listing the contacts;
  • another one for populating the SELECT control used for presenting the type of contact (we can all agree that this is not a grid, right?:) ).

Here’s the final markup I’ve ended up using:

<div id="mainView"
     class="sys-template"
     sys:attach="dv"
     dv:data="{{person}}">
     <label for="name">Name:</label>
     <input type="text" name="name" 
sys:value="{binding name}" /> <br /> <label for="name">Address:</label> <input type="text" name="name"
sys:value="{binding address}" /> <table> <thead> <tr> <td>Contact</td> <td>type</td> </tr> </thead> <tbody sys:attach="dv" class="sys-template" dv:data="{binding contacts}"> <tr> <td> <input type="text"
sys:value="{binding contact}" /> </td> <td> <select id="contactTypes" sys:attach="dv" class="sys-template" sys:value=
"{binding type, convert=getId, convertBack= getContactType}" dv:data="{{ contactTypes }}"> <option sys:value="{{id}}">
{{description}}
</option> </select> </td> </tr> </tbody> </table> </div> <input type="button" value="print info" id="print" />

There are a couple of interesting things going on here:

  • the top DataView control is used for allowing me to use templates (which rely on bindings) for filling the form automatically and setting the context for the inner DataView controls;
  • the second DataView control displays a grid which shows the contacts for the current person. As you can see, it’s really similar to what” we’ve used before.
  • the third DataView is applied…to a SELECT element. We need to fill the select with the available contact type options and the easiest way to do that is to simply associate it with a DataView control and set its data to the contactTypes object. However, we need to select the correct type for the “current” contact and that’s where the sys:value enters the scene.

Btw, we do need to define two convert functions for ensuring proper setting of each of objects that participate in the binding relationship. Here’s the code for those functions:

Sys.converters.getId = function (value, binding) {
  return value.id;
};
Sys.converters.getContactType = function (val, binding) {
  for (var i = 0; i < contactTypes.length; i++) {
    if (contactTypes[i].id == val) {
      return contactTypes[i];
    }
  }
  //probably should throw here?
  return null;
};

The getId conversion function is invoked when the value is being propagated from the person’s contact object to the dropdown. In this case, we only need the ID in order to select the correct OPTION; on the other hand, when the value is being propagated from the dropdown to the “current” contact, we do need to convert the OPTION’s value into an object (and that’s why we’re using a for loop in the getContactType method). Btw, here’s another picture which shows that alterations are in fact propagated back to the object:

complex2

Even though I’m not showing the code for print button, I can assure you that it’s the longest method of this demo page. As you can see, the DataView is really a useful control. Combining it with templates and bindings does really cut down the code needed for several real world scenarios.

And that’s it for now. Stay tuned for more!