
It is common to see, in web applications, Gmail-like UIs, where you show a list of items (emails in the case of Gmail), and where you'd like users to be able to perform actions on multiple items at a time. For this, users need to be able to select items. This can be done by adding a checkbox at the beginning of each line. It is easy enough to list your items in XForms with an
<xforms:repeat>
, but developers often wonder how to add that checkbox at the beginning of every line.
Let's consider a practical case:
- You have an instance with a list of countries. Each country has a code, which can be used as a key to identify the country.
- You'd like the selected countries to be stored in a separate instance, as a space separated list of country codes.
- You don't want to change the instance that contains the list of countries in any way (no adding of an attribute or element "selected" for each country).
- You want to generate a UI like the one shown along this text.
The trick here is to have:
- One
<xforms:select appearance="full">
control per line.
- All the
<xforms:select appearance="full">
have exactly one item, each with a different value (the country code) and they are all bound to the same node.
Show me the code! The space separated list of country codes will go in the root element of the selected instance:
<xforms:instance id="selected">
<selected />
</xforms>
And finally the
<xforms:repeat>
which iterates over the countries and generates the
<xforms:select appearance="full">
looks like:
<xforms:repeat nodeset="instance('countries')/country">
<xxforms:variable name="country" select="."/>
<xhtml:tr>
<xhtml:td>
<xforms:select appearance="full" ref="instance('selected')">
<xforms:item>
<xforms:label/>
<xforms:value value="$country/us-code"/>
</xforms:item>
</xforms:select>
</xhtml:td>
<xhtml:td>
<xforms:output value="name"/>
</xhtml:td>
<xhtml:td>
<xforms:output value="us-code"/>
</xhtml:td>
</xhtml:tr>
</xforms:repeat>
This works because the XForms select is non-destructive: when you uncheck a a checkbox from a specific XForms select, the engine will only remove the value corresponding to the checkbox you unchecked, and will leave other values in the space separated list unchanged. Job done!