Last modified on 9 July 2009, at 20:22

XForms/Repeat filter

MotivationEdit

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.

MethodEdit

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 ImagesEdit

Before FilterEdit

Before Filter

After FilterEdit

After Filter and Select

Link to working XForms applicationEdit

Repeat Filter

Sample ProgramEdit

<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>

DiscussionEdit

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 postion 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.

AttributionEdit

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