XForms/Repeat filter

Motivation edit

You want to dynamically display a list of items that match an input field as you type. This is character-by-character incremental filtering of possible options. The difference between this and other "suggest" options is that the list of possible options can be stored in an instance.

Method edit

We will put all of the possible choices inside of a xf:repeat statement. When the user types in the input field we will narrow down the choices using an XPath expression in the repeat xf:nodeset attribute. The XPath expression will only match items that begin with specific characters in the xf:input field.

Screen Images edit

Before Filter edit

 
Before Filter

After Filter edit

 
After Filter and Select

Link to working XForms application edit

Repeat Filter

Sample Program edit

<html xmlns="http://www.w3.org/1999/xhtml" 
  xmlns:xf="http://www.w3.org/2002/xforms"
  xmlns:ev="http://www.w3.org/2001/xml-events"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <head>
      <xf:model>
         <xf:instance id="data" xmlns="">
            <data>
               <item>
                  <title>red</title>
               </item>
               <item>
                  <title>orange</title>
               </item>
               <item>
                  <title>yellow</title>
               </item>
               <item>
                  <title>green</title>
               </item>
               <item>
                  <title>blue</title>
               </item>
               <item>
                  <title>indigo</title>
               </item>
                <item>
                  <title>violet</title>
               </item>
               <item>
                  <title>black</title>
               </item>
                <item>
                  <title>biege</title>
               </item>
               <item>
                  <title>brown</title>
               </item>
            </data>
         </xf:instance>
         <xf:instance id="search" xmlns="">
            <search>
               <filter />
            </search>
         </xf:instance>
         <xf:instance id="selected-data" xmlns="">
            <data>
               <item />
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <xf:input ref="instance('search')/filter" incremental="true">
         <xf:label>Starts with filter: </xf:label>
      </xf:input>
      <br />
      <xf:repeat
          nodeset="instance('data')/item[title[starts-with(., instance('search')/filter)]]" 
          id="data-list">
         <xf:trigger>
            <xf:label>Select</xf:label>
            <xf:action ev:event="DOMActivate">
               <xf:setvalue
                   ref="instance('selected-data')/item" 
       value="instance('data')/item[title[starts-with(.,instance('search')/filter)]][index('data-list')]/title" /> 
            </xf:action>
         </xf:trigger>
         <xf:output ref="title" />
      </xf:repeat>
      <xf:output ref="instance('selected-data')/item">
         <xf:label>Selected: </xf:label>
      </xf:output>
   </body>
</html>

Discussion edit

The most challenging part of this example is the value attribute of the setvalue element:

<xf:setvalue
    ref="instance('selected-data')/item" 
    value="instance('data')/item[title[starts-with(.,instance('search')/filter)]][index('data-list')]/title" />

We are setting the item of the selected-data instance: ref=instance('selected-data')/item

We need to set it to the selected value - but the 2nd part - [index('data-list')] - is the numeric index of the selected item in the filtered list. This is why we 1st have to filter the list and 2nd choose the right index out of the filtered list.

Just like in the restriction of the nodeset attribute of the repeat we are re-running the XPath expression and getting all of the items that start with the text in the filter.

instance('data')item[title[starts-with(.,instance('search')/filter)]]

Note that this is exactly the same expression as in the repeat nodeset attribute.

This list is additionally constrained with the position of the selected item on the data-list:

[index('data-list')]

We are really doing consecutive filters on two sets of data. The first generates the same list as the search. The second uses the item selected to select the correct item.

Attribution edit

This example was originally posted on the mozilla XForms developer group by Chris Sw... on Aug 1st of 2007. A bug was found and fixed by Sivaram Arabandi.

Next Page: Inline Repeats | Previous Page: Repeat into table
Home: XForms