One of the most sorely missed features in HTML forms comes by many names: tables, grid controls, or line items. The basic concept is that many forms in common use don't fit in well with a flat list of form controls. Figure 6.11, “Repeating line items in X-Smiles” shows one embodiment of this, rendered in the X-Smiles browser.
Another common scenario is a purchase order, with repeating lines, each containing quantity, description, price, and computed extended price.
The primary means of accomplishing this in XForms is the repeat element, which operates over homogeneous collections, the same as itemset, described earlier. The nodeset attribute of repeat selects a number of nodes, and the contents of the element, both from XForms and from the host language, are effectively repeated once for each resulting node. One way to think of this is to "unroll" the repeat, so that the following:
<repeat nodeset="item"> <input ref="@quantity" .../> </repeat>
has a similar effect, when the nodeset returns three item nodes, to:
<input ref="item/@quantity" .../> <input ref="item/@quantity" .../> <input ref="item/@quantity" .../>
The main difference between a repeat element and unrolled syntax (besides convenience) is how the result is presented to the user. The repeat version makes it possible to show more items in a limited space, as in the case of scroll bars. Attributes of repeat further refine this by specifying how the initial appearance should be:
Items can be added and removed from repeat with the XForms Actions insert and delete, which are given as examples here and described fully in chapter Chapter 7, Actions and Events.
Every repeat has a current position, called an index. The concept of index extends the concept of focus, so that if a form control in a repeat has focus, then the item that contains that form control is the current index. The XPath function index( ) returns the current index of any repeat. This is useful for inserting at or removing the current item, as the following example shows:
<model> <instance> <items xmlns=""> <item quantity="1" price="2.34"/> </items> </instance> </model> ... <repeat nodeset="items/item" id="r1"> <input ref="@quantity" .../> <output ref="@price" .../> </repeat> <!-- insert just after the index item --> <trigger> <label>Insert</label> <insert nodeset="/items/item" at="index('r1')" position="after"/> <setvalue ref="/items/item[index('r1')]/@quantity">0</quantity> <setvalue ref="/items/item[index('r1')]/@price">0.00</setvalue> </trigger> <!-- delete the index item --> <trigger> <label>Delete</label> <delete ev:event="DOMActivate" nodeset="/items/item" at="index('r1')"/> </trigger>
One problem that arises with the repeat element is that a host language might not be able to add arbitrary elements where a repeating structure is needed. A prime example of this is HTML table. It would be natural to express a repeating sequence as table rows or table cells (or a nested repeat with both). The problem with that is that if XHTML allowed repeat in the content model of table or tr, that would open the floodgates and allow all kinds of non-table related markup. For cases like these, the XForms specification defines special attributes that can be included in a host language, if needed. The attributes all share the same prefix: repeat-nodeset, repeat-model, repeat-bind, repeat-startindex, and repeat-number. The first three of these work just like the unprefixed node-set binding attributes, and the last two work just like the corresponding attributes on repeat. The table example in XHTML, with repeating table rows, looks like this:
<table repeat-nodeset="item"> <tr> <td><output ref="@quantity" .../></td> <td><output ref="@price" .../></td> </tr> </table>