Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Make Data Islands Work in All Browsers : Page 4

XML Data Islands and XML Data Sources aren't a new idea—and they are no longer exclusive to Internet Explorer, either. Here's how to use data islands generically, without getting locked in to any one vendor's implementation, and make your data-centric Web pages work across all modern browsers.


advertisement
Implementing the Binding
I'm going to jump forward a little bit and show you the final binding logic. Here's the bind() method.
The numbered comments refer to the planning list earlier in this article.

bind : function () { // 1. Find all the datasources in the page. var targets = this.getElementsByAttribute( document,'datasource'); if (!targets || targets.length == 0) return; // Do it for each data binding 'target' in // the page for (var i=0; i < targets.length; i++) { var iid = targets[i].getAttribute('datasource'); var island = document.getElementById(iid); if (!island) return; // 2. Extract a copy of the current content // for this target var template = targets[i].cloneNode(true); // ... and delete the real copy for (var j = targets[i].childNodes.length-1; j>=0; j--) { targets[i].removeChild( targets[i].childNodes.item(j)); } if ( this.isMSIE ) { island = this.makeIEtree(island); } // 4. Apply the template once for each // XML record for (j = 0; j < island.childNodes.length; j++) { // children that are text nodes aren't // real records var record = island.childNodes.item(j); if ( record.nodeName == '#text' ) continue; // 5, 6. Combine page, template and data this.merge(targets[i], template, record); } if ( this.isMSIE ) { delete island; } } }

There's an outside loop for each data source, and an inside loop for each record. When the code finds a datasource tag, you want to replace its content. That entails extracting its content from the page, working on it, and putting it back. The final content combines the DOM subtrees pointed to by the template and islands. Because there might be more than one record per data source, you might have to put it back several times.

The one wrinkle in this is (from a standards point of view) IE's vile behavior. When extracting the data island, IE returns a node, but you can't walk the subtree underneath that node. Instead, IE gives back a flat list of start tags, text and end tags. The makeIEtree() function takes this mess and creates a proper DOM tree out of it. You can see it created and then destroyed on either side of steps 4-6. Here's the code:

makeIEtree : function (island) { var subtree = document.createElement(island.nodeName); var current = subtree; var next; for (var j = 0; j < island.childNodes.length; j++) { var record = island.childNodes.item(j); if ( record.nodeName == '#text' ) { current.appendChild( document.createTextNode(record.nodeValue)); } else if ( record.nodeName.charAt(0) == '/' ) { current = current.parentNode; } else { next = document.createElement( record.nodeName); current.appendChild(next); current = next; } } return subtree; },

This method has a simple loop that runs through the mess that IE returns. The subtree variable is the top of the DOM tree being built; current points to the sub-part of the subtree that's being created; and next is used temporarily to create nodes. Each time the code identifies a new tag, it creates a node and current steps down into it. Each time it identifies a closing tag, current steps back up one node. Otherwise, it just adds whatever is found to the set of child nodes for the current node.

With that obstacle out of the way, all that's left to do is process the found information each time. That's the province of the merge() method:



merge : function (target, template, record) { // dig out the fields requiring update var fields = this.getElementsByAttribute(template,'datafield'); if (!fields || fields.length == 0) next; // update text for target fields in the template for (var k=fields.length-1; k>=0; k--) { var thetag = fields[k]; var thefield = thetag.getAttribute('datafield'); var newtext = this.getFieldDataFromRecord(record,thefield); if (thetag.firstChild) // replace existing text { thetag.firstChild.nodeValue = newtext; } else if ( thetag.value == null ) // not form tag { thetag.appendChild( document.createTextNode(newtext)); } else // a form element { thetag.value = newtext; } } // put the updated content back into the page. for (k=0; k < template.childNodes.length; k++) { target.appendChild( template.childNodes.item(k).cloneNode(true)); } },

First, the merge method finds all the datafield-laden tags in the target and puts them into an array. Then, for each one, it finds any matching content in the supplied record. There are three cases to consider when putting that matched content into the template (the original page content). Either the content tag already contains text (replace), or it doesn't (add), or it's a form element, in which case the data should go into the value property. Finally, it copies everything in the updated template back into the page itself. All done—all you have to do to make it run is load the page. You can download the sample code and try it in your preferred browser.

Notice that this more professional DHTML code is free of many of the older worries: we don't have event handlers embedded in the page; there's a reduced emphasis on browser-specific tests (only do that when there's no choice), and the effect that's being achieved is serious and meaningful, not a gimmick or a distraction. With the explosive influence of AJAX and other DHTML-related techniques lately, expect to see more of this kind of thing in practitioner's work and in client demands.

Data islands are easy to implement cross-browser using a little generic code. This article shows how to display data-island driven content, including integrating that content into forms, tables and non-tabular markup like lists. With a little more effort you could extend this into a sophisticated data management system, and indeed, a number of experiments have been performed in that area. With the demise of ancient browsers such as IE 4.0 and Netscape 4.x, and the rise of Mozilla and Firefox, DHTML is a more powerful and generally applicable technique than it ever was before. Unlock your IE-specific applications with modern DHTML.

Editor's Note: The editorial staff of DevX would like to add our condolences to the voices of so many around the Web. Our longtime author and friend, Nigel McFarlane, passed away in June 2005. This article is one of two that Nigel wrote for us before his death; they are published with the permission of his family. Nigel McFarlane was the author of two books and a freqent contributor to Mozilla and the open source movement, as well as to DevX. —Lori Piquet



The late Nigel McFarlane was a freelance science and technology writer, and a leading commentator on Mozilla and Firefox technology. He was the author of "Firefox Hacks" published by O�Reilly Media and "Rapid Application Development with Mozilla" for Prentice Hall PTR and a frequent contributor to the open source movement.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date