9 XForms User Interface

This chapter covers XForms features for combining form controls into user interfaces.

All form controls defined in 7 Form Controls are treated as individual inline units for purposes of visual layout e.g., in XHTML processing. Aggregation of form controls with markup defined in this chapter provides semantics about the relationship among user interface controls; such knowledge can be useful in delivering a coherent UI to small devices. For examle, if the user interface needs to be split up amongst several screens, controls appearing inside the same aggregation would typically be rendered on the same screen or page.

9.1 Grouping Form Controls

The group element is used as a container for defining a hierarchy of form controls. Groups can be nested to create complex hierarchies.

Example: XML Representation: <group>
<group
  (single node binding attributes)
  (common attributes)
>
  <!--  ((any form control) | group | repeat | component | switch )* -->
</group>

(single node binding attributes) - Selection of instance data node, defined at 7.14.2 Single Node Binding Attributes
(common attributes) - defined in 7.14.1 Common Attributes

In CSS-based layout systems, groups lay out their children using a constraint-based system that supports both relative flexible sizing and intrinsic sizing. Through CSS, an inline box can be specified using the display property with a value of inline. A block-level group can be specified with a value of block, which is the default.

The hierarchy defined by nested group elements is used to determine the traversal order specified by attribute navIndex on form controls. Setting the input focus on a group results in the focus being set to the lowest form control in the tabbing order within that group.

9.2 Conditional Constructs For Dynamic User Interfaces

The XForms User Interface allows the authoring of dynamic user interfaces, i.e., user interfaces that vary based on the current state of the instance data being populated. As an example, portions of a questionnaire pertaining to the user's automobile may become relevant only if the user has answered in the affirmative to the question 'Do you own a car?'. Another use case for such dynamic user interfaces is when the underlying XForms Model contains conditional structures.

This element contains one or more case elements. Each case has an id attribute that is used within event handlers appearing within form controls to activate or deactivate that portion of the user interface created by the markup contained within that case element.

Example: switch

This example shows how to provide a conditional user interface--either input or output:

<switch id="sw">
 <case id="in">
  <input ref="yourname">
   <caption>Please tell me your name</caption>
  </input>
 </case>
 <case id="out">
  <html:p>Hello <output ref="yourname" />.</html:p>
 </case>
</switch>

The above will result in the portion of the user interface contained within the default case being initially displayed. The XForms Action toggle activates and deactivates different portions of this conditional construct.

Example: XML Representation: <switch>
<switch
  (single node binding attributes)
  (common attributes)
  default = xsd:IDREF
>
  <!-- case+ -->
</switch>

(single node binding attributes) - Selection of instance data node, defined at 7.14.2 Single Node Binding Attributes
(common attributes) - defined in 7.14.1 Common Attributes
default = xsd:IDREF - optional selector for initial case.

Example: XML Representation: <case>
<case
  id = xsd:ID
>
  <!--  ##any -->
</case>

id = xsd:ID - required unique identifier.

Issue (issue-switch-scroll):

In addition to toggle, the XForms Action scroll might be used within switch to cycle through the various contained case clauses.

9.3 Repeating Structures

The XForms Model allows the definition of repeating structures such as multiple items being purchased within a purchase order. When defining the XForms Model, such higher-level aggregations are constructed out of basic building blocks; similarly, here are defined higher-level user interface constructs that build on the form controls defined previously that can bind to data structures such as lists and collections.

Element repeat represents a UI mappings over homogenous collection, in other words, a collection consisting entirely of like form controls.

<repeat nodeset="/cart/items/item">
  <input ref="." .../><html:br/>
</repeat>

Note that controls for adding or removing repeating entries may appear within the repeat, (causing the add/remove controls themselves to repeat), or may appear outside the repeat.

Another way to view the repeat processing (modulo special user interface interactions) is to consider "unrolling" the repeat. The above example is similar to the following (assuming four item elements in the returned node-set):

<!-- unrolled repeat -->
<input ref="/cart/items/item[1]" .../><html:br/>
<input ref="/cart/items/item[2]" .../><html:br/>
<input ref="/cart/items/item[3]" .../><html:br/>
<input ref="/cart/items/item[4]" .../><html:br/>

Notice that the model item for the collection being populated would typically have defined attributes minOccurs and maxOccurs; these values will in turn determine if the user agent displays appropriate UI controls for the user to add or delete entries in the collection. Event listeners separately control UI aspects such as scrolling and insertion. This specification does not specify normative means for displaying such add and delete controls; as with the rest of the XForms User Interface design, these are left to be flexible while showing a default presentation.

Example: XML Representation: <repeat>
<repeat
  (nodeset binding attributes)
  (common attributes)
  startIndex = xsd:positiveInteger : 1
  number = xsd:nonNegativeInteger
>
  <!-- ##any -->
</repeat>

(nodeset binding attributes) - Selection of context node-set, defined at 7.14.3 Nodeset Binding Attributes
(common attributes) - defined in 7.14.1 Common Attributes
startIndex = xsd:positiveInteger : 1 - 1-based hint to the XForms Processor as to which starting element from the collection to display.
number = xsd:nonNegativeInteger - hint to the XForms Processor as to how many elements from the collection to display.

9.3.1 Repeat Processing

The user interface markup for repeating structures adds encapsulation metadata about the collection being populated. Processing for repeating structures takes into account a cursor that points to a current item. This cursor is used as a reference point for insert and delete XForms Actions. These, along with setRepeatCursor, can be thought of as the markup equivalent of limited DOM access to the markup constructed by repeat.

Notice that the contained XForms form controls inside element repeat do not explicitly specify the index of the collection entry being populated. This is intentional; it keeps both authoring as well as the processing model simple. But as a consequence, the user interface cannot bind to an element from the underlying collection out of sequence except by using an absolute XPath expression.

The binding expression attached to the repeating sequence returns a node-set of the collection being populated, not an indiviual node. Within the body of element repeat binding expressions are evaluated with a context node of the node determined by the repeatCursor.

A simple but powerful consequence of the above is that if the XForms Model specifies nested collections, then a corresponding user interface can nest repeat elements. The form controls appearing inside repeat need to be suitable for populating individual items of the collection.

The XForms Actions enumerated at 8 XForms Actions may be used within event listeners attached to button elements placed inside the body of construct repeat. In combination with the facilities provided by element group and CSS layout, this allows document authors to customize the positioning of controls for standard actions such as insert or delete.

9.3.2 User Interface Interaction

As specified, element repeat allows us to bind a user interface to a dynamic homogenous collection.

The number of displayed items might be less than the total number available. In such a case, the presentation would only render a portion of the repeating items at a given time. For example, a graphical user interface might present a scrolling table. The attributes startIndex and number provide hints to the user interface as to which elements should be displayed initially.

The XForms Actions setRepeatCursor and scroll adjust the internal startIndex as needed to ensure that currently active items in the repeating sequence are presented to the user.

9.4 Dynamic Selection Choices

XForms defines list controls selectOne and selectMany. By default, these follow the standard form control behavior of representing their state as a Schema simpleType that is associated with an instance data node--often a derived-by-list datatype. Often, a more convenient representation for lists is using markup instead of whitespace to separate list items. This section explains additional XForms processing to handle this common case.

Notice that this usage matches the case of selection controls selectOne and selectMany where the user is allowed to select from a set of dynamic choices, i.e., where the list of choices is determined at run-time as opposed to authoring time. As a consequence, this working draft proposes the construct repeat as the means to represent dynamic choices for controls selectOne and selectMany.

In this case, binding attribute nodeset on element repeat specifies the location in the instance that contains the dynamically determined set of choices. The contained form controls within element repeat specify the user interface for one element from the dynamic list as before. Semantics of the repeat cursor are as defined earlier.

<selectOne ref="/trip/reservation/flight">
  <caption>Available Flights</caption>
  <help>Displaying list of available flights matching your
        requirements, please pick one.</help>
  <!-- /trip/available/flights is populated by a sequence of -->
  <!-- <flight> elements  at run time-->
  <repeat nodeset="/trip/availableFlights/flight">
     <!--itemrefs that point to <flight> nodes -->
  </repeat>
</selectOne>

In the above, the user is able to select a flight from a dynamically created list of available flights. The user interface template encapsulated within the body of element repeat is used in creating a choice item for each flight element found in /trip/availableFlights.

9.5 Reusable Form Controls

User Interface templates allow the creation of reusable user interface components. Just as authors can define data types and structures that can be reused within the XForms Model, reusable user interface components allow us to design complex user interfaces using the basic building blocks described in the previous section, and then reuse these components in multiple situations. As with any component framework, this has two basic requirements:

This section describes such a component framework along with sample markup. This component mechanism has some similarities with the user interface used within the body of element repeat to provide the user interface for a generic element of the nodeset operated on by element repeat. Those templates can be thought of as anonymous components. This consists of:

  1. XForms user interface construct defComponent defined next corresponds to creating re-usable data types.

  2. Using XForms user interface construct component to instantiate reusable components declared using defComponent corresponds to creating data instances corresponding to a reusable user defined data type.

this example, assume that USShippingAddress is a reusable data type that is used in multiple places in the XForms Model, e.g. the user will be asked for a billingAddress and shippingAddress--both of type USShippingAddress.

The following shows a simple example that is designed to bind an XForms form control to a model item of type address with no attention to making the component reusable.

<group ref="address">
  <input ref="street">
    <caption>Please enter your street address</caption>
  </input>
  <input ref="zip">
    <caption>Zip Code</caption>
  </input>
</group>

Next, consider the above fragment modified to become a reusable component that could be used for obtaining both the shipping and billing address. To do this, those portions of the component that the caller will wish to modify need to be parameterized.

<defComponent id="AddressWidget">
  <param name="streetPrompt"/>
  <param name="zipPrompt"/>
  <group ref="address">
    <input ref="street">
      <caption><valueOf select="$streetPrompt"/></caption>
    </input>
    <input ref="zip">
      <caption><valueOf select="$zipPrompt"/></caption>
    </input>
  </group>
</defComponent>

Note that the markup shown above does not create a user interface; user interface is created by explicitly instantiating the component via element component described next.

With this, the component can be instantiate in the user interface for obtaining the shipping and billing address:

<component ref="myAddress" component="AddressWidget">
  <param name="streetPrompt" value="Shipping Street Address"/>
  <param name="zipPrompt" value="Zip Code for shipping state"/>
</component>

The reusable component is instantiated by element component; parameter values are specified by the contained param elements.

Example: XML Representation: <defComponent>
<defComponent
  id = xsd:ID
>
  <!--  param*, ((any form control) | group | repeat | component | switch )* -->
</defComponent>

id = xsd:ID - required unique identifier.

Example: XML Representation: <param>
<param
  id = xsd:ID
  name = xsd:NMTOKEN
  value = xsd:string
>
  <!--  ##empty -->
</param>

id = xsd:ID - optional unique identifier.
name = xsd:NMTOKEN - required parameter name
value = xsd:string - optional parameter value

Example: XML Represenatation: <valueOf>
<valueOf
  id = xsd:ID
  select = xsd:string
>
  <!--  ##empty -->
</valueOf>

id = xsd:ID - required unique identifier.
select = xsd:string - reference to a parameter

Example: XML Representation: <component>
<component
  (single node binding attributes)
  (common attributes)
  component = xsd:IDREF
>
  <!-- param* -->
</component>

(single node binding attributes) - Selection of instance data node, defined at 7.14.2 Single Node Binding Attributes
(common attributes) - defined in 7.14.1 Common Attributes
component = xsd:IDREF - reference to the defComponent.