Once you learn how to create templates and modify datasources, the
ultimate in template mastery is to apply datasources to a template
dynamically.
This process is done through the database property
of a XUL element that contains a template. The object returned by
this property has only two methods, AddDataSource
and RemoveDataSource. A separate
builder.rebuild function is also available for
refreshing the template's display, but you probably
won't need it once the template automatically
updates itself. The addition and removal of a datasource to a
<tree> template is demonstrated here:
tree = document.getElementById('tree-template');
tree.database.AddDataSource(someDatasource);
// tree will now update its display to show contents
tree.database.RemoveDataSource(someDatasource);
// tree will now be empty
// Optional, use only when tree is not updating for some reason
tree.builder.rebuild( );
You can add and remove any datasource as long as the template
actually matches the data inside it. Also, multiple datasources can
be applied to the same template with no problems, which allows you to
aggregate data from different places, such as contact data, work
information, and computer hardware information (e.g.,
"Eric uses a Compaq with the serial number
1223456-1091 to write his book and he sits on the fourth floor of the
Acme Building, which is the Bay Area branch of Acme Enterprises.)
Putting templates inside
XBL can be a useful organizational scheme. Here is a basic
implementation of a widget that creates a list of people based on
names listed in an attribute:
<people names="Brian King,Eric Murphy,Ian Oeschger,Pete Collins,David Boswell"/>
Obviously, the comma is used as the delimiter for this list. The
constructor element in Example 10-11 uses JavaScript
to break up this string.
Example 10-11. Binding with in-memory datasource and <listbox> template
<?xml version="1.0"?>
<bindings xmlns ="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="people">
<implementation>
<constructor>
<![CDATA[
// Read the Names into an Array
names = document.getAnonymousNodes(this)[0].getAttribute('names');
names = new String(names);
namesArray= names.split(',');
// Initialize the RDF Service
rdf = Components
.classes['@mozilla.org/rdf/rdf-service;1']
.getService(Components.interfaces.nsIRDFService);
// Initialize a Datasource in Memory
inMemory = '@mozilla.org/rdf/datasource;1?name=in-memory-datasource';
datasource = Components.classes[inMemory].
createInstance(Components.interfaces.nsIRDFDataSource);
// Create the Root Node and an Anonymous Resource to Start With
root = rdf.GetResource('urn:root');
people = rdf.GetAnonymousResource( );
// Insert the People resource into the RDF graph
datasource.Assert
(root,
rdf.GetResource('http://www.mozdev.org/rdf#people'),
people,true);
// Initialize Methods needed for Containers
rdfc = Components
.classes['@mozilla.org/rdf/container-utils;1']
.getService(Components.interfaces.nsIRDFContainerUtils);
// For the People resource, make a Sequence of people
peopleSequence = rdfc.MakeSeq(datasource, people);
for(i=0;i<namesArray.length;i++)
{
// Create a Person, with a Unique Number, for example
person = rdf.GetResource(i);
// Insert the Person's name into the RDF graph underneath number
datasource.Assert
(person,
rdf.GetResource('http://www.mozdev.org/rdf#name'),
rdf.GetLiteral(namesArray[i]),true);
peopleSequence.AppendElement(person);
}
list = document.getAnonymousNodes(this)[1];
list.database.AddDataSource(datasource);
]]>
</constructor>
</implementation>
<content>
<xul:box id="names" inherits="names" flex="0"/>
<xul:listbox datasources="rdf:null" ref="urn:root" flex="1">
<xul:template>
<xul:rule>
<xul:conditions>
<xul:content uri="?uri"/>
<xul:triple subject="?uri"
predicate="http://www.mozdev.org/rdf#people"
object="?people"/>
<xul:member container="?people" child="?person"/>
<xul:triple subject="?person"
predicate="http://www.mozdev.org/rdf#name"
object="?name"/>
</xul:conditions>
<xul:action>
<xul:listitem uri="?person">
<xul:listcell>
<xul:description value="?person "/>
<xul:description value="?name"/>
</xul:listcell>
</xul:listitem>
</xul:action>
</xul:rule>
</xul:template>
</xul>
</content>
</binding>
</bindings>
In Example 10-11, everything you need to display a
datasource dynamically is present. The only difference between this
dynamically generated version and a static RDF-based template is the
datasources="rdf:null", which specifies that the
template does not refer to an actual datasource. Data that is edited,
rearranged, or changed in a different way is often displayed
dynamically in the UI with templates in this manner.