XForms/Dynamic Selection Lists

From Wikibooks, open books for an open world
Jump to: navigation, search

Motivation[edit]

You want that the content of a selection list to depend on the value another selection list. This is also known as "Cascading Selection".

Method[edit]

We have two instances in a model. The first instance populates the first select1 list. The second select1 uses an xf:itemset to only select the relevant items from the second instance. In effect we are adding a "where" clause to the list of items selected in the second list.

The presented form shows an example where the user can select a season (Spring, Summer,...) and in a second select the user will only be able to select from the relevant month in that season.

We also will automatically set the month to null when the season selection changes to make sure our pairing is always valid.

The example had been tested with Firefox 2.0.0.12 and the Mozilla XForms add on 0.8.4 as well as on FireFox 3.0.

Screen Image[edit]

Cascading Selects

Link to XForms Application[edit]

Load Example XForms Application

Note that the initial values of the selections are set in the instance values.

Sample Program[edit]

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:xf="http://www.w3.org/2002/xforms"
      xmlns:ev="http://www.w3.org/2001/xml-events">
   <head>
      <title>Test conditional selection lists</title>
      <xf:model>
 
         <xf:instance id="selected-values" xmlns="">
            <data>
               <selected-season>Winter</selected-season>
               <selected-month>January</selected-month>
            </data>
         </xf:instance>
 
         <xf:instance id="seasons" xmlns="">
            <root>
               <item name="Spring"/>
               <item name="Summer"/>
               <item name="Autumn"/>
               <item name="Winter"/>
            </root>
         </xf:instance>
 
         <xf:instance id="months" xmlns="">
            <root>
               <item name="January" season="Winter"/>
               <item name="February" season="Winter"/>
               <item name="March" season="Spring"/>
               <item name="April" season="Spring"/>
               <item name="May" season="Spring"/>
               <item name="June" season="Summer"/>
               <item name="July" season="Summer"/>
               <item name="August" season="Summer"/>
               <item name="September" season="Autumn"/>
               <item name="October" season="Autumn"/>
               <item name="November" season="Autumn"/>
               <item name="December" season="Winter"/>
            </root>
         </xf:instance>
         <xf:bind id="selected-season" nodeset="instance('selected-values')/selected-season"/>
      </xf:model>
   </head>
   <body>
      <p>Test conditional selection lists -
         month selector depends on the current season</p>
 
         <xf:select1 ref="instance('selected-values')/selected-season">
           <xf:label>Season:</xf:label>
           <xf:itemset nodeset="instance('seasons')/item">
             <xf:label ref="@name"/>
             <xf:value ref="@name"/>
           </xf:itemset>
           <!-- As soon as you chance this value we set the month to be blank -->
           <xf:action ev:event="xforms-value-changed">
              <xf:setvalue ref="instance('selected-values')/selected-month" value="''"/>
           </xf:action>
         </xf:select1>
         <br/>
         <xf:select1 ref="instance('selected-values')/selected-month">
           <xf:label>Month:</xf:label>
           <xf:itemset nodeset="instance('months')/item[@season=instance('selected-values')/selected-season]">
             <xf:label ref="@name"/>
             <xf:value ref="@name"/>
           </xf:itemset>
         </xf:select1>
         <br/>
         <xf:output ref="instance('selected-values')/selected-season">
            <xf:label>selected-season: </xf:label>
         </xf:output>
		  <br/>
 
         <xf:output ref="instance('selected-values')/selected-month">
            <xf:label>selected-month: </xf:label>
         </xf:output>
 
         <h4>Relevant Months using Repeat</h4>
	   <xf:repeat nodeset="instance('months')/item[@season=instance('selected-values')/selected-season]">
		   <xf:output ref="@name"/>
	   </xf:repeat>
 
   </body>
</html>

Updating the Second Select When the First Select Changes[edit]

Note that we have added an action and trap the xforms-value-changed event to the first select1 statement. We use the xf:setvalue event to change the value of the second select1 to be blank. This will guarantee that the pair of values will always be consistent.

<xf:select1>
.....
     <!-- As soon as you chance this value we set the month to be null -->
     <xf:action ev:event="xforms-value-changed">
          <xf:setvalue ref="instance('selected-values')/selected-month" value="''"/>
     </xf:action>
</xf:select1>

This suggestion was made by Aaron Reed.


Next Page: Deep Copy with Insert Origin | Previous Page: Referencing Items

Home: XForms