Recipe3.8.Dynamically Changing Select Options Using JavaScript


Recipe 3.8. Dynamically Changing Select Options Using JavaScript

Problem

You want to use JavaScript to dynamically change the items displayed in an HTML select element based on data retrieved from your application's model.

Solution

Use the Struts logic:iterate tag to create JavaScript arrays for the different option sets. Then use a JavaScript onchange event handler to change the options set at runtime. Example 3-8 shows a complete JSP page where the JavaScript arrays are dynamically created using Struts tags. The changeOptions event handler function resets the options for the select control using the JavaScript arrays.

Example 3-8. Generating DHTML using Struts
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <html> <head>     <title>Struts - JavaScript Example</title>     <script language="JavaScript">         // Create the array for the first set of options         fooArray = new Array( );         <logic:iterate  index                       name="MyForm"  property="fooList">             fooArray[<bean:write name="ctr"/>] =                  new Option("<bean:write name='fooValue'/>",                            "<bean:write name='fooValue'/>",                            false, false);         </logic:iterate>         // Create the array for the second set of options         barArray = new Array( );         <logic:iterate  index                       name="MyForm"  property="barList">             fooArray[<bean:write name="ctr"/>] =                  new Option("<bean:write name='barValue'/>",                            "<bean:write name='barValue'/>",                            false, false);         </logic:iterate>         function changeOptions(var control) {                    // control is the triggering control             // baz is the select control             baz = document.MyForm.baz;             baz.options.length=0;             if (control.value == 'Foo')                  bazArray = fooArray;             else                 bazArray = barArray;             for (i=0; i < bazArray.length; i++)                baz.options[i] = bazArray[i];         }     </script> </head> <body>     <html:form name="MyForm" action="processMyForm">         <html:radio property="fooBar" value="Foo"                       onclick="changeOptions(this);"/> Foo<br/>         <html:radio property="fooBar" value="Bar"                       onclick="changeOptions(this);"/> Bar<br/>         Baz: <html:select property="baz">                       </html:select>     </html:form> </body> </html>

Discussion

You can use Struts to generate JavaScript as you can use it to generate HTML. Some developers consider JavaScript "evil"; in reality, it's only "slightly wicked." Take a pragmatic approach: If JavaScript makes your application better and your users happier, then use it. But, use it in such a way that your business logic stays in the business layer, and not slapped on the web page. Struts helps you do just this.

A concrete example can illustrate this approach. Suppose you want to ask a user to select his favorite programming language and, subsequently, favorite Integrated Development Environment (IDE) for the selected language. The language will be chosen using radio buttons, and the IDE will be selected from a drop-down menu. If the language is Java, then the IDE drop-down will display options such as Eclipse, Net Beans, IDEA, etc. If the language is C#, then the drop-down will display Visual Studio and SharpDevelop.

Example 3-9 shows the action form that holds this data.

Example 3-9. ActionForm for favorite language/IDE
package com.oreilly.strutsckbk; import org.apache.struts.action.ActionForm; public final class MyForm extends ActionForm  {          private static String[] javaIdes =          new String[] {"Eclipse", "IDEA", "JBuilder",                         "JDeveloper", "NetBeans"};     private static String[] csharpIdes =          new String[] {"SharpDevelop", "Visual Studio"};          public String[] getJavaIdes( ) {return javaIdes;}     public String[] getCsharpIdes( ) {return csharpIdes;}          public String getLanguage( ) {         return language;     }          public void setLanguage(String language) {         this.language = language;     }     public String getIde( ) {         return ide;     }     public void setIde(String ide) {         this.ide = ide;     }     private String language;     private String ide; }

Example 3-10 shows the JSP (favorite_language.jsp) that renders the input page. This example is similar to the Solution.

Example 3-10. JSP Page using Struts-rendered DTHML
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <html> <head>   <title>Struts - JavaScript Example</title>   <script language="JavaScript">      // Create the array for the first set of options      javaIdesArray = new Array( );      <logic:iterate  index                    name="MyForm"  property="javaIdes">           javaIdesArray[<bean:write name="ctr"/>] =               new Option("<bean:write name='ide'/>",                         "<bean:write name='ide'/>",                         false, false);      </logic:iterate>      // Create the array for the second set of options      csharpIdesArray = new Array( );      <logic:iterate  index                    name="MyForm"  property="csharpIdes">           csharpIdesArray[<bean:write name="ctr"/>] =               new Option("<bean:write name='ide'/>",                         "<bean:write name='ide'/>",                         false, false);      </logic:iterate>      function changeOptions(control) {               ideControl = document.MyForm.ide;        ideControl.options.length=0;        if (control.value == 'Java')           ideArray = javaIdesArray;        else          ideArray = csharpIdesArray;        for (i=0; i < ideArray.length; i++)            ideControl.options[i] = ideArray[i];      }   </script> </head> <body>   <html:form action="/admin/ViewFavoriteLanguage">       What's your favorite programming language?<br/>       <html:radio property="language" value="Java"                     onclick="changeOptions(this);"/> Java<br/>       <html:radio property="language" value="C-Sharp"                     onclick="changeOptions(this);"/> C-Sharp<br/>       <p>What's your favorite development tool?<br/>       IDE: <html:select property="ide"/>       </p>       <html:submit/>   </html:form> </body> </html>

The script block nested in the head element contains the JavaScript. The logic:iterate tags loop over JavaBean properties to create two JavaScript arrays: one for the Java IDEs and one for the C# IDEs. Each array contains a set of Option JavaScript objects. The Option object represents an option of an HTML select control. This object takes four parameters in the constructor: the text value to display, the value to pass when the form is submitted, a Boolean indicating if the value is the default selected value, and another Boolean indicating if the value is currently selected.

The JavaScript function for changing the options comes after the logic:iterate loop. This function is pure static JavaScript. The radio button that triggers the change is passed as the parameter to the function. If the current value of the radio button control is Java, then the select control is populated with the Option objects representing the Java IDEs. Otherwise, the control is populated with the Option objects representing the C# IDEs.

The HTML body contains the form, rendered using the Struts html tags. The Struts tags support the JavaScript change listeners via the onfunction attributes. For radio buttons, the onclick listener works well. The single parameter passed to the function, this, is a reference to the HTML radio button. When the page is initially rendered, the display should look something like Figure 3-1.

Figure 3-1. Form using DHTML and Struts


Once you click one of the radio buttons, the options in the drop-down list for the IDE field are populated with the data originally from the form bean. Figure 3-2 shows the display when you click the Java radio button.

Figure 3-2. Dynamically rendered drop-down menu


Similarly, if you click the C-Sharp radio button, the values in the drop-down list change to reflect the values from the corresponding JavaScript array.

JSTL can be used instead of the Struts bean and logic tags. In this case, you use the JSTL c:forEach and c:out tags instead of logic:iterate and bean:write. These tags generate the JavaScript array in the same manner as the Struts tags:

javaIdesArray = new Array(  ); <c:forEach var="ide" varStatus="status"           items="${MyForm.javaIdes}">    javaIdesArray[<c:out value="${status.index}"/>] =     new Option("<c:out value='${ide}'/>",               "<c:out value='${ide}'/>",               false, false); </c:forEach>

JavaScript programming can be frustrating, particularly for the Java developer used to strong typing and compile-time checks. However, providing this type of dynamic

client-side interaction can lead to a much richer end-user experience.

See Also

JavaScript: The Definitive Guide by David Flanagan (O'Reilly) is invaluable when it comes to JavaScript programming. If business logic is required to determine the dynamic data, then Recipe 3.9 provides a better approach.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net