Chapter 11. Introduction to Databinding

Table of Contents

1. Introduction
2. The Basics
2.1. Multiple Rows of Data
3. Ways to Include Data
3.1. Embedded Data
3.2. Included Data
3.3. HTTP Data
4. Datapointers
4.1. Differential Debugging SWF and DHTML

1. Introduction

We shall be examining how to interact with data in LZX.

2. The Basics

As far as importing data into an LZX app is concerned, we always work in XML. The XML declaration is not required, but a single root XML node is. Data is represented by the <dataset> element.

Example 11.1. Datasets

<canvas height="80" width="100%">
  <dataset name="myData">
    <myXML>
      <person show="simpsons">
        <firstName>Homer</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Marge</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Montgomery</firstName>
        <lastName>Burns</lastName>
      </person>
    </myXML>
  </dataset>
  
  <text datapath="myData:/myXML[1]/person[1]/firstName[1]/text()"/>
</canvas>

In the above example, the single root element is myXML. The datapath attribute of the <text> tag binds it to the data.

Datapaths use XPath attributes to navigate through the XML data. So the name of the dataset to use goes before the colon myData:, followed by the nodes, separated by forward slashes (/). The square brackets provide a (one-based) space to enter which sibling node we want.

In plain English, the above example says: "get me the text from the first firstName node, of the first person node of the first (and of course, only) myXML node." The text() method call returns that node's text.

To get Marge's name, we could rewrite the <text> tag as follows:

<text datapath="myData:/myXML/person[2]/firstName/text()" /> 

To get the show attribute of Montgomery, we could write:

<text datapath="myData:/myXML/person[3]/@show" /> 

The /text() path segment is unnecessary with the datapath attribute.

So far we've used the <text> tag in conjunction with a single datapath. If we wanted to present tabular information, this would mean each text element would need its own datapath, and would be cumbersome and difficult to write. Instead let's make a quick table, by giving a <view> a datapath:

Example 11.2. Assigning a datapath to a view

<canvas height="80" width="100%">
  <dataset name="myData">
    <myXML>
      <person show="simpsons">
        <firstName>Homer</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Marge</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Montgomery</firstName>
        <lastName>Burns</lastName>
      </person>
    </myXML>
  </dataset>

  <view name="rowOfData" datapath="myData:/myXML[1]/person[1]">
    <simplelayout axis="x"/>
    <text datapath="firstName/text()"/> 
    <text datapath="lastName/text()"/> 
    <text datapath="@show"/>
  </view>
</canvas>

The datapath of the entire rowOfData view has now become Homer's person node. The child elements of rowOfData inherit this, so their datapaths can be referenced relatively.

2.1. Multiple Rows of Data

In the above example we used a single rowOfData node. Next, we use a range of nodes:

Example 11.3. Range of nodes

<canvas height="80" width="100%">
  <dataset name="myData">
    <myXML>
        <person show="simpsons">
          <firstName>Homer</firstName>
          <lastName>Simpson</lastName>
        </person>
        <person show="simpsons">
          <firstName>Marge</firstName>
          <lastName>Simpson</lastName>
        </person>
        <person show="simpsons">
          <firstName>Montgomery</firstName>
          <lastName>Burns</lastName>
        </person>
      </myXML>
  </dataset>

  <view name="myTable">
    <simplelayout axis="y"/>
    <view name="rowOfData" datapath="myData:/myXML[1]/person">
      <simplelayout axis="x"/>
      <text datapath="firstName/text()"/> 
      <text datapath="lastName/text()"/> 
      <text datapath="@show"/>
    </view>
  </view>
</canvas>

Whichever tag contains the datapath attribute will get repeated as often as is necessary.

Remember that datapaths bind themselves to a view, so if the data changes, so will the view. We shall come to that a little later.

3. Ways to Include Data

So far we've been using embedded data (XML that is written into the document). This is fine for very small amounts of static data, but there are other methods better suited to larger (or dynamic) data.

How is it included? When is it loaded? Syntax
Embedded Compile-time
<dataset name="myData">
  <myXML>
     <!-- ... other XML tags ... -->
  </myXML>
</dataset>
Included Compile-time
<dataset name="myData" src="myXMLDoc.xml"/>
HTTP data Runtime
<dataset name="myData" request="true" 
         type="http" src="myXMLDoc.xml" />

3.1. Embedded Data

Embedded data is XML between the <dataset> tags. When the OpenLaszlo Server compiles the application, the data is bound into it. The data can still be changed after the application runs. Included data is static.

3.2. Included Data

Included data is essentially the same as embedded data, except that the XML itself is kept in a separate file. The size of the initial download will be the same as with embedded data.

It is locally referenced via the filesystem, so it can be placed in other directories. Included data is static.

3.3. HTTP Data

Remote data goes over HTTP, which means it can (but doesn't have to) be dynamic. If it is static, then the only difference between it and included or embedded data is that it is downloaded after the application loads. The type="http" attribute indicates that this is an HTTP request. The requests can be either GET or POST.

There are several points at which the client requests the data:

  • The client will request the data as soon as the app loads if the dataset's request attribute is true.

  • If the autorequest attribute is set to "true", the client will also request the data every time the querystring or base URL of the dataset changes (using the setQueryString() or setSrc('src', ...) respectively) methods of the lz.dataset object.

  • When the dataset's doRequest method gets called.

In the table above, we referenced a file locally (myXMLDoc.xml), but we could have done it absolutely, or we could have hit a server-side (PHP, ASP, JSP or some CGI) that returned an XML document. We could add the query string to the <dataset> tag:

<dataset name="myData"
         src="http://www.myServer.com/cgi-bin/myXMLDoc.cgi?return=addresses"/>

The type="http" attribute gets implied when the src attribute contains "http://".

4. Datapointers

Datapaths are extremely handy, but if you need more control over the data, they can become cumbersome. Datapaths are actually extensions of datapointers, but are easier to learn, which is why we introduced them first. A datapointer is a pointer into the dataset, which can be moved around. It can only be in one place of the dataset at a time, but you can have multiple datapointers, each pointing to a different part of a dataset.

Datapointers are not bound to views like datapaths are, but they do have a place in the view hierarchy (that is, they know about parents and children).

You will use a datapointer when you need to operate on the data in some way. For example, using the same format of data as in the previous examples, say you wanted to find all the people who were in the South Park show:

Example 11.4. Manipulating Datapointers

<canvas height="50" width="100%">
  <text id="sometext"/>
  <dataset name="myData" src="resources/myShowData.xml"/>
  <datapointer xpath="myData:/myXML" ondata="processData()"> 
    <method name="processData"> 
      this.selectChild(); 
      do 
      { 
      if (this.xpathQuery( '@show' ) == 'south park') 
        { 
        sometext.addText(this.xpathQuery('firstName/text()') + "\n");      
        } 
      } while (this.selectNext()); 
    </method> 
  </datapointer> 
</canvas>

We are including the data from a local file. You can download that XML file here, and here's what it looks like:

    <myXML>
      <person show="simpsons">
        <firstName>Homer</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Marge</firstName>
        <lastName>Simpson</lastName>
      </person>
      <person show="simpsons">
        <firstName>Montgomery</firstName>
        <lastName>Burns</lastName>
      </person>
      <person show="south park">
        <firstName>Eric</firstName>
        <lastName>Cartman</lastName>
      </person>
      <person show="south park">
        <firstName>Stan</firstName>
        <lastName>Marsh</lastName>
      </person>
    </myXML>

The first time the selectChild() method is called, it selects the first <person> node.

The selectNext() method call returns true as long as an XML node was successfully selected (that is, until there aren't any more). We exploit this by using it in a do ... while loop, so that the same iteration occurs for every <person> node.

We could also have given the <datapointer> onerror and ontimeout event handlers to capture any problems.

4.1. Differential Debugging SWF and DHTML

When you query or manipulate an invalid datapointer, in the past, you got back `undefined`. In DHTML, this often led to disaster down the road, so the compiler added a warning when you did this, but still returned `undefined` for backwards compatibility.