Create a data binding solution for Firefox
Takeaway: One fact that sets Firefox apart from Internet Explorer is that it provides support for XBL (eXtensible Binding Language). Here's an examination of how XBL is important for binding data fields to XML data islands.
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.
Print/View all Posts Comments on this article
SponsoredWhite Papers, Webcasts, and Downloads
- TCP/IP Troubleshooting Global Knowledge
- 2008 IT Salary and Skills Report Global Knowledge
- The OSI Model: Understanding the Seven Layers of Computer Networks Global Knowledge
Article Categories
- Security
- Security Solutions, IT Locksmith
- Networking and Communications
- E-mail Administration NetNote, Cisco Routers and Switches
- CIO and IT Management
- Project Management, CIO Issues, Strategies that Scale
- Desktops, Laptops & OS
- Windows 2000 Professional, Microsoft Word, Microsoft Excel, Microsoft Access, Windows XP,
- Data Management
- Oracle, SQL Server
- Servers
- Windows NT, Linux NetNote, Windows Server 2003
- Career Development
- Geek Trivia
- Software/Web Development
- Web Development Zone, Visual Basic, .NET
