Mozilla’s Firefox browser is becoming a
favorite among Web application developers, including myself. One
fact that sets Firefox apart from Internet Explorer is that it
provides support for XBL (eXtensible Binding Language). XBL offers
the facilities to bind behaviors to DOM/HTML elements. Let’s
examine how XBL is important for binding data fields to XML data
islands.

One of the privileges available to developers
who create IE solutions is data binding to data source objects
including XML data islands. In IE, XML data islands are created as
separate DOMDocuments within the existing page, which itself is a
DOMDocument. This gives all the functionality of the DOMDocument.
For instance, you can load new data by using the load() or
loadXML() methods or select individual nodes using XPath
queries.

In Mozilla, XML data islands are viewed as any
other element within the DOM of the page. This means that in order
to get any functionality from it, you’ll need to add the behaviors
to the data fields for updating any of the underlying data. You can
also get the bound values and populate the data fields upon loading
the page.

Let’s say that you have an XML data island that
contains basic user information, e.g., the user’s name, address,
and telephone number. Here’s the XML that covers that data:

<xml id=”xmlData”
style=”visibility:hidden;”>
    <userInfo>
       
<first_name>John</first_name>
        <last_name>Doe</last_name>

        <street>123
Some Street</street>
       
<city>Smalltown</city>
       
<state>US</state>
       
<postal>99999</postal>
       
<telephone>8005551212</telephone>
    </userInfo>
</xml>

The only thing that’s special about this data
island is the style attribute. Without hiding the XML data island,
Mozilla browsers will display the content of the individual
nodes.

Next, you should add the data fields to your
page:

<body onload=”document_onload()”>
<form id=”theForm”>
    <input type=”text” id=”txtFirstName”
value=”” dataFld=”first_name”
 class=”linked_data”/><br>
    <input type=”text” id=”txtLastName” value=””
dataFld=”last_name”
 class=”linked_data”/><br>
    <input type=”text” id=”txtStreet”
value=”” dataFld=”street”
 class=”linked_data”/><br>
    <input type=”text” id=”txtCity”
value=”” dataFld=”city”
 class=”linked_data”/><br>
    <input type=”text” id=”txtState”
value=”” dataFld=”state”
class=”linked_data”/><br>
    <input type=”text” id=”txtPostal”
value=”” dataFld=”postal”
 class=”linked_data”/><br>
    <input type=”text” id=”txtPhone”
value=”” dataFld=”telephone”
class=”linked_data”/><br>
<textarea cols=”80″ rows=”10″
id=”txtXmlData”></textarea>
</form>
</body>

Notice the class and dataFld attributes of the
INPUT elements. The class attribute adds the behavior you specify
with XBL, and the dataFld attribute specifies the node to which
you’re binding.

IE developers will recognize the dataFld
attribute. However, in Mozilla browsers, this doesn’t automatically
bind the data to the XML data island, so you have to add the XBL
behavior.

In order to bind the elements, specify the
location of your binding in your CSS:

<style>
.linked_data {
    -moz-binding:
url(linked_data.xml#link);
}
</style>

Here’s the XBL code that will accomplish
updating the data when the data changes:

<?xml version=”1.0″?>  
<xbl:bindings
xmlns:xbl=”http://www.mozilla.org/xbl”>  
    <xbl:binding id=”link”>
        <xbl:implementation>

            <xbl:property
name=”linkedNode”/>
            <xbl:method
name=”update”>
                <xbl:parameter
name=”newValue”/>
                <xbl:body>

                    alert(“udpate
method called with param ” + newValue + “.”);
                   
this.linkedNode.nodeValue = newValue;
                    alert(“success”);

                </xbl:body>

            </xbl:method>

            <xbl:method
name=”bind”>
                <xbl:body>

                    this.linkedNode
=
document.getElementById(“xmlData”).getElementsByTagName(this.getAttribute

(“dataFld”))[0].childNodes[0];
                    this.value
= this.linkedNode.nodeValue;
                   
document.getElementById(“txtXmlData”).value =
 getInnerXml(document.getElementById(“xmlData”));
                </xbl:body>

            </xbl:method>

        </xbl:implementation>

        <xbl:handlers>

            <xbl:handler
event=”change”>
                this.update(this.value);

            </xbl:handler>

        </xbl:handlers>

    </xbl:binding>
</xbl:bindings>

Within the binding, you created a property
called linkedNode. This
property will contain the actual text node object that houses the
data for the bound element. You also added two methods, update and bind. The update method takes one
parameter: the new value of the bound data. The bind method binds the bound
control to the xml node through the linkedNode property. This is
done during the page’s onload event.

Finally, an event handler is added for the change event, which fires
when the control loses focus after the value changes. When the change event occurs, the
binding uses the update
method and passes the bound element’s value property.

Now you need to complete the data binding by
setting the bound elements’ values during the page’s onload event:

<script language=”JavaScript”>

function document_onload() {
   
document.getElementById(“txtFirstName”).bind();
   
document.getElementById(“txtLastName”).bind();
   
document.getElementById(“txtStreet”).bind();
   
document.getElementById(“txtCity”).bind();
   
document.getElementById(“txtState”).bind();
   
document.getElementById(“txtPostal”).bind();
   
document.getElementById(“txtPhone”).bind();
    document.getElementById(“txtXmlData”).value
=
 getInnerXml(document.getElementById(“xmlData”));
}

</script>

You simply use the bind method to complete this
task. To check your work, I suggest using a simple function to
write out my XML to the txtXmlData TEXTAREA during the load and change events (I had to do
this since Firefox doesn’t recognize the innerHTML property on the
XML element):

var
ELEMENT_NODE                   =
1;
var
ATTRIBUTE_NODE                 =
2;
var
TEXT_NODE                      =
3;
var
CDATA_SECTION_NODE             =
4;
function getInnerXml(node) {
    var s = “<” + node.nodeName;
    if (node.hasChildNodes()) {
    for (var i = 0; i <
node.childNodes.length; i++) {
            if
(node.childNodes[i].nodeType == TEXT_NODE)
                s
+= “>” + node.childNodes[i].nodeValue;
            if
(node.childNodes[i].nodeType == ELEMENT_NODE)
                s
+= getInnerXml(node.childNodes[i]);
        }
        s += “</” +
node.nodeName + “>”;
    } else {
        s +=
“/>”;
    }
    return s;
}

If you would like the source code to this
article as tested in Firefox Version 1.0.1, you can check it out here
or here.

Keep your developer skills sharp by automatically signing up for TechRepublic’s free Web Development Zone newsletter, delivered each Tuesday.