How to populate the second select according the the chosen option in the first select?

user1459961 picture user1459961 · Aug 1, 2012 · Viewed 7k times · Source

I'm using struts2-jquery-plugin. Normally in my form, I need my first select to be populated from database by School Subjects and according to the chosen school subject I need to update the second select and populate it from database by the Teachers who teach that subject.

I found in the following link the sample code above, but I can't guess much how it works. They don't explain it. http://struts2-jquery.appspot.com/home.action# .

Am I forced to use JSON? Any explaination or a code to help me in my issue would be so appreciated.

<label>First Select:</label> 
<sj:select id="firstSelect" name="firstSelect" onChangeTopics="firstSelectChanged" src="firstSelect.action"/> 
<label>Second Select:</label> 
<sj:select id="secondSelect" reloadTopics="firstSelectChanged" src="secondSelect.action" elementIds="firstSelect"/>

Update

I tried this link http://struts.jgeppert.com/struts2-jquery-showcase/index.action ( the section Ajax Link > AJAX Select) suggested in this post by nmc but I get this error :

Struts Problem Report
Struts has detected an unhandled exception: 

Messages: •There is no Action mapped for namespace / and action name echo.



--------------------------------------------------------------------------------

Stacktraces
There is no Action mapped for namespace / and action name echo. - [unknown location] 
    com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:177)
    org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:61)
    org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
    com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:47)
    org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:458)
    org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:395)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    java.lang.Thread.run(Unknown Source)

The java Action class :

package test.action;

import java.util.ArrayList;
import java.util.List;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;

import com.opensymphony.xwork2.ActionSupport;

@ParentPackage( value = "showcase")
public class JsonSample extends ActionSupport {

      private static final long   serialVersionUID = -2223948287805083119L;
      private List<String>        languageList;
      private List<String>        reloadList;
      private String              language;

      @Actions( {
        @Action(value = "/jsonsample", results = {
          @Result(name = "success", type = "json")
        })
      })
      public String execute()
      {


        languageList = new ArrayList<String>();

        languageList.add("Java");
        languageList.add("PHP");
        languageList.add("C#");

        reloadList = new ArrayList<String>();
        if (language != null && language.equalsIgnoreCase("Java"))
        {
          reloadList.add("Struts2");
          reloadList.add("MyFaces");
          reloadList.add("Tapestry");
        }
        else if (language != null && language.equalsIgnoreCase("PHP"))
        {
          reloadList.add("CakePHP");
          reloadList.add("Symfony");
          reloadList.add("Zend");
        }
        else if (language != null && language.equalsIgnoreCase("C#"))
        {
          reloadList.add("NStruts");
          reloadList.add("ProMesh.NET");
          reloadList.add("Websharp");
        }

        return SUCCESS;
      }

      public String getJSON()
      {
        return execute();
      }

      public List<String> getLanguageList()
      {
        return languageList;
      }

      public List<String> getReloadList()
      {
        return reloadList;
      }

      public void setLanguage(String language)
      {
        this.language = language;
      }

    public String getLanguage() {
        return language;
    }

    public void setLanguageList(List<String> languageList) {
        this.languageList = languageList;
    }

    public void setReloadList(List<String> reloadList) {
        this.reloadList = reloadList;
    }

}   

The JSP page :

<s:form id="formSelectReload" action="echo" theme="simple" cssClass="yform">
        <fieldset>
            <legend>AJAX Form</legend>
            <div class="type-text">
                <label for="language">Language: </label>
                <s:url id="remoteurl" action="jsonsample"/> 
                <sj:select 
                    href="%{remoteurl}" 
                    id="language" 
                    onChangeTopics="reloadsecondlist" 
                    name="language" 
                    list="languageList" 
                    listKey="myKey" 
                    listValue="languageList" 
                    emptyOption="true" 
                    headerKey="-1" 
                    headerValue="Please Select a Language"
                />
            </div>
            <div class="type-text">
                <label for="echo">Framework: </label>
                <s:url id="remoteurl" action="jsonsample"/> 
                <sj:select 
                    href="%{remoteurl}" 
                    id="selectWithReloadTopic" 
                    formIds="formSelectReload" 
                    reloadTopics="reloadsecondlist" 
                    name="echo" 
                    list="reloadList" 
                    emptyOption="true" 
                    headerKey="-1" 
                    headerValue="Please Select a Framework"
                />
            </div>
            <div class="type-button">
                <sj:submit 
                    id="submitFormSelectReload"
                    targets="result" 
                    value="AJAX Submit" 
                    indicator="indicator" 
                    button="true"
                    />
                    <img id="indicator" 
                        src="images/indicator.gif" 
                        alt="Loading..." 
                        style="display:none"
                    />
            </div>
        </fieldset>
    </s:form>

When I deleted action="echo" from the form, I had no more error but as a result I've got kind of inclusion shown in the picture. When I click on Ajax Submit, instead of that I get the selected option in the result, I get the form in the result div. Thank you so much again.

enter image description here

Answer

nmc picture nmc · Aug 1, 2012

I think you'll find the example at http://struts.jgeppert.com/struts2-jquery-showcase/index.action more helpful as they also have the Java code. Look under Ajax Forms --> AJAX Select (Doubleselect).

The documentation also has some good code examples.

Some things to note:

The action must return JSON.

That is, the action that populates your select list as referred to in the href attribute of your <sj:select> tag has to return JSON as annotated in the example by:

@Actions({
    @Action(
    value="/jsonsample",
    results={
    @Result(name="success",type="json")
    })
})

There is also a way to specify this in struts.xml file. There should be plenty of examples of this here on Stackoverflow and around the internet.

Your second select should include formIds attribute

It specifies the form(s) whose field values should be serialized and sent with the request. This is how the action that populates your second list receives the value which is set in the first list.