BasicsA very common requirement of user interfaces consists in repeating visual elements, such as rows in a table or entries in a list. Those repeated sections usually (but not always) have an homogeneous aspect: they all have the same or a very similar structure. For example, multiple table rows will differ only in the particular content they display in their cells. An example of this is an invoice made of lines with each a description, unit price, and quantity.
XForms provides a very powerful mechanism to implement such repeated
structures: the
<xforms:repeat>xhtml:tr></xhtml:tr></xforms:repeat>
This is not enough to be functional code: you need to indicate to the
<xforms:instance id="employees-instance">
Assuming you want to produce one table row per employee, add the
following <xforms:repeat nodeset="instance('employees-instance')/employee"> <xhtml:tr>...</xhtml:tr></xforms:repeat>
This produces automatically three <xforms:repeat nodeset="instance('employees-instance')/employee"> <xhtml:tr> <xhtml:td> <xforms:output ref="first-name"/> </xhtml:td> </xhtml:tr></xforms:repeat>
This works because for each iteration, the context node for the
Repeat index
Each NOTE: With XForms 1.1, each nested repeat keeps its own separate index value. NOTE: XForms 1.1 does not explicitly limit in what type of XPath expressions index()
can be used. However, in Orbeon Forms, it is strongly advised at the
moment to only use
index() within actions, and to avoid using it in control
bindings and binds, as
doing so may yield unpredictable results.
Deleting iterations with the <xforms:delete> action
<!-- This deletes the last element of the collection --><xforms:delete nodeset="employees" at="last()"/><!-- This deletes the first element of the collection --><xforms:delete nodeset="employees" at="1"/><!-- This deletes the currently selected element of the collection (assuming the repeat id 'employee-repeat') --><xforms:delete nodeset="employees" at="index('employee-repeat')"/><!-- This deletes all elements of the collection --><xforms:delete nodeset="employees"/>NOTE: Prior to XForms 1.1, the at attribute was mandatory. Since
XForms 1.1, it is
optional, and if omitted the nodeset attribute specifies
all the nodes to
remove.
Inserting iterations with the <xforms:insert> actionSee also the Insert a new item into a repeat how-to guide.
<!-- This inserts a copy of the template before the last element of the collection --><xforms:insert nodeset="employees" at="last()" position="before"/><!-- This inserts a copy of the template after the last element of the collection --><xforms:insert nodeset="employees" at="last()" position="after"/><!-- This inserts a copy of the template before the first element of the collection --><xforms:insert nodeset="employees" at="1" position="before"/><!-- This inserts a copy of the template after the first element of the collection --><xforms:insert nodeset="employees" at="1" position="after"/><xforms:insert nodeset="employees" at="last()" position="after"/><!-- This inserts a copy of the template before the currently selected element of the collection --><xforms:insert nodeset="employees" at="index('employee-repeat')" position="before"/><!-- This inserts a copy of the template after the currently selected element of the collection --><xforms:insert nodeset="employees" at="index('employee-repeat')" position="after"/>NOTE: Orbeon Forms supports the new XForms 1.1 features as well, including the
origin
and context
attributes. The
XForms 1.1 specification features a more complete list of
example.
The Using <xforms:trigger> to execute actions
Insertions and deletions are typically performed when the user of the
application presses a button, with the effect of adding a new repeated
element before or after the currently selected element, or of deleting
the
currently selected element. You use an <xforms:trigger> <xforms:label>Add</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:insert nodeset="employees" at="index('employee-repeat')" position="after"/> </xforms:action></xforms:trigger>or: <xforms:trigger> <xforms:label>Delete</xforms:label> <xforms:action ev:event="DOMActivate"> <xforms:delete nodeset="employees" at="index('employee-repeat')"/> </xforms:action></xforms:trigger>
Note that we use <xforms:trigger> <xforms:label>Add</xforms:label> <xforms:insert ev:event="DOMActivate" nodeset="employees" at="index('employee-repeat')" position="after"/></xforms:trigger>or: <xforms:trigger> <xforms:label>Delete</xforms:label> <xforms:delete ev:event="DOMActivate" nodeset="employees" at="index('employee-repeat')"/></xforms:trigger>
Notice in that case how Nested repeatsIt is often desirable to nest repeat sections. Consider the following XForms instance representing a company containing departments, each containing a number of employees: <xforms:instance id="departments"> <departments> <department> <name>Research and Development</name> <employees> <employee> <first-name>John</first-name> </employee> <employee> <first-name>Mary</first-name> </employee> </employees> </department> <department> <name>Support</name> <employees> <employee> <first-name>Anne</first-name> </employee> <employee> <first-name>Mark</first-name> </employee> <employee> <first-name>Sophie</first-name> </employee> </employees> </department> </departments></xforms:instance>This document clearly contains two nested sections subject to repetition:
Following the example above, here is how departments and employees can be represented in nested tables with XForms: <xhtml:table> <xforms:repeat nodeset="instance('departments')/department"> <xhtml:tr> <xhtml:td> <xforms:output ref="name"/> </xhtml:td> <xhtml:td> <xhtml:table> <xforms:repeat nodeset="employees/employee"> <xhtml:tr> <xhtml:td> <xforms:output ref="first-name"/> </xhtml:td> </xhtml:tr> </xforms:repeat> </xhtml:table> </xhtml:td> </xhtml:tr> </xforms:repeat></xhtml:table>
In the code above, the second Iterating over plain valuesXForms 1.1 only specifies iterating over instance data nodes (elements or attributes). As of January 2010, Orbeon Forms supports iterating over values, for example: <xforms:repeat nodeset="(1 to 10)"> <xforms:output value="position()"/> <xforms:output value="."/></xforms:repeat>In this case, the context item within the repeat is a number, not a node. NOTE: It is hoped that the XForms specification will include this possibility in the future. Possibly, a new attribute, such as |