Using custom controls in a form

In this section we'll look at all the ways that a custom control can be used in a form. A custom control can be used anywhere that the base control can be used which is particularly useful when using custom controls based on xf:output, since they can be used in labels, such as for controls or in selection lists, messages, including hints and help, and so on. Custom controls can also make use of instance data in the same way that any other control can.

String literals

The simplest use of a custom control is when the 'value' associated with the control is set using an XPath string literal. Using the example of a custom control that shows a map, we might set the longitude and latitude as follows:

<xf:output value="'51.523004;-0.106859'" appearance="geolocation" style="width: 200px; height: 100px;" />

Using dynamic instance data

Once again using the example of a map control, if the location for the map could change, we can place the data in an instance and refer to it using a binding expression on the control:

<xf:model>
  <xf:instance>
    <instanceData xmlns="">
      <location>51.523004;-0.106859</location>
    </instanceData>
  </xf:instance>
</xf:model>
.
.
.
<xf:output ref="location" appearance="geolocation" />

The data could now be changed either by loading some new instance data--from a server or local file--or by the user interacting with another control on the form. For example, an xf:input control would allow the user to edit the location directly:

<xf:input ref="location">
  <xf:label>Change location:</xf:label>
</xf:input>

and any time this value was changed, the location of the map in the xf:output control would also be updated.

Another approach would be to use two xf:range controls to control the longitude and latitude independently:

<xf:model>
  <xf:instance>
    <instanceData xmlns="">
      <location long="51.523004" lat="-0.106859" />
    </instanceData>
  </xf:instance>
  <xf:bind nodeset="@long | @lat" type="xs:integer" />
</xf:model>
.
.
.
<xf:group ref="location">
  <xf:range ref="@long" incremental="true">
    <xf:label>Longitude:</xf:label>
  </xf:range>
  <xf:range ref="@lat" incremental="true">
    <xf:label>Latitude:</xf:label>
  </xf:range>
  <xf:output value="concat(@long, ';', @lat)" appearance="geolocation" />
</xf:group>

Note that since our custom control requires only one value as input, we have to concatenate the longitude and latitude values. Also note that by using @incremental on our xf:range controls we can update the image as the user moves the slider.

Calculated values

Of course, we could use both techniques; we could have a map that is centred on the value from the instance data, and then another map alongside it that shows the location that is on the other side of the world, calculated using the instance data for the first map:

<xf:model>
  <xf:instance>
    <instanceData xmlns="">
      <location long="51.523004" lat="-0.106859" />
    </instanceData>
  </xf:instance>
  <xf:bind nodeset="@long | @lat" type="xs:integer" />
</xf:model>
.
.
.
<xf:group ref="location">
  <xf:range ref="@long" incremental="true">
    <xf:label>Longitude:</xf:label>
  </xf:range>
  <xf:range ref="@lat" incremental="true">
    <xf:label>Latitude:</xf:label>
  </xf:range>
  <xf:output value="concat(@long, ';', @lat)" appearance="geolocation">
    <xf:label>Your location:</xf:label>
  </xf:output>
  <xf:output value="concat(@long - 180, ';', @lat)" appearance="geolocation">
    <xf:label>Other side of the world:</xf:label>
  </xf:output>
</xf:group>

Using xf:repeat to show a list of controls

Since our map is a control like any other, we can also use it as part of a xf:repeat. In this example we have some instance data which is a list of locations, and then we use a xf:repeat to render a map for each one:

<xf:model>
  <xf:instance>
    <instanceData xmlns="">
      <locations>
        <location long="51.501383" lat="-0.139239">Home</location>
        <location long="51.523004" lat="-0.106859">Office</location>
        <location long="48.851049" lat="2.282238">XTech 2007</location>
        <location long="51.163898" lat="-115.564413">WWW 2007</location>
      </locations>
    </instanceData>
  </xf:instance>
</xf:model>
.
.
.
<xf:repeat nodeset="location">
  <xf:output value="concat(@long, ';', @lat)" appearance="geolocation">
    <xf:label ref="." />
  </xf:output>
</xf:repeat>

Selection labels

It's also possible to use custom controls based on xf:output in selection lists. In this example we use the same list as before, but instead of a simple repeat, we use the locations to create a list of maps that the user can choose from:

<xf:model>
  <xf:instance>
    <instanceData xmlns="">
      <locations current-location="">
        <location long="51.501383" lat="-0.139239">Home</location>
        <location long="51.523004" lat="-0.106859">Office</location>
        <location long="48.851049" lat="2.282238">XTech 2007</location>
        <location long="51.163898" lat="-115.564413">WWW 2007</location>
      </locations>
    </instanceData>
  </xf:instance>
</xf:model>
.
.
.
<xf:output ref="@current-location">
  <xf:label>Current location:</xf:label>
</xf:output>
<xf:select1 ref="@current-location">
  <xf:label>Where are you now?:</xf:label>
  <xf:itemset nodeset="../location">
    <xf:label>
      <xf:output ref="." />:
      <xf:output value="concat(@long, ';', @lat)" appearance="geolocation" />
    <xf:label>
    <xf:value value="concat(@long, ';', @lat)" />
  </xf:itemset>
</xf:select1>

Messages, hints and help

One last use of custom controls that it is worth drawing attention to is their use in messages, help text and hints. For example, if we wanted a tooltip on an xf:input control, that helped the user by showing a map that reflected the current location, we could mark it up like this:

<xf:input ref="@current-location">
  <xf:label>Change location:</xf:label>
  <xf:hint>
    You may want to change your location. Your current location is here:
    <br />
    <xf:output ref="." appearance="geolocation" style="width: 150px; height: 150px;" />
  </xf:hint>
</xf:input>

Similarly, we might want to provide some detailed help to our users (when they press [F1] in a control), and part of that help text might require a map:

<xf:input ref="@current-location">
  <xf:label>Change location:</xf:label>
  <xf:help>
    This control allows you to choose a location. You are currently here:
    <br />
    <xf:output ref="." appearance="geolocation" style="width: 100px; height: 100px;" />
    <br />
    but you could go here:
    <br />
    <xf:output value="'51.523004;-0.106859'" appearance="geolocation" style="width: 100px; height: 100px;" />
  </xf:help>
</xf:input>

Both xf:hint and xf:help are specific forms of xf:message and as you would expect, custom controls could also be used inside messages. For example, the following is a simple message that is activated by a xf:trigger:

<xf:trigger>
  <xf:label>Get a message</xf:label>
  <xf:message level="modal" ev:event="DOMActivate">
    This is where you could be:
    <br />
    <xf:output value="'51.523004;-0.106859'" appearance="geolocation" style="width: 100px; height: 100px;" />
  </xf:message>
</xf:trigger>

In the next section we'll look at how we can build some controls.