jspstruts2struts

Struts2 select tag - Dynamically add options


I'm working on migrating a Struts1 project to Struts2. And I have encountered the following piece of code.

<html:select ...>
  <logic:iterate id="something" name="" type="">
    <logic:equal name="something" property="" value="">
      <html:option value=""><bean:write ... /></html:option>
    </logic:equal>
  </logic:iterate>
</html:select>

It checks the value in the iterator and add options to the select list dynamically if the condition is met.

How can I achieve something similar with Struts2 select tag.

AFAIK, Struts2 select tag won't even work properly with plain html option tag.


Solution

  • Indeed Struts2 <s:select> tag doesn't allow to use html option tags in the body of the tag. This is because it's using list attribute to provide data in the form of an object with key/value pairs. You can use listKey and listValue to define which properties of the object will be used for rendering options. You can see UI Tags Reference Guide for <s:select> tag. It has many attributes that allows you to customize rendering HTML.

    Practical usage of the select tag: it's rarely used. It's useful if you want to show fixed size lists or a map created via OGNL in the JSP.

    For example:

    <s:select label="Months"
           name="months"
           headerKey="-1" headerValue="Select Month"
           list="#{'01':'Jan', '02':'Feb', [...]}"
           value="selectedMonth"
           required="true"
    />    
    

    For big lists consider to use an <sj:autocompleter> widget. You can also use an autocompleter as select box or select widget as autocompleter. All examples of select and autocompleter widgets you can see in Struts2 Jquery Showcase.

    When migrating from Struts1 to Struts2 you have faced with the problem of presenting rendered html select tag because Struts2 doesn't allow options inside the body of the tag. So constructing the list of options could be made in the prepare() method of the action. An example of this usecase you can find via reading this answer.

    Why this approach is preferable because you are working with the model from the controller, not from the view, and when the model is ready to display you are using some tags or widgets to render html or populate DOM. Or you can use Ajax or Angular services to load a model from the Struts2 controller. The data is transferred in the JSON format. JSON is very powerful tool to transfer data between Java and JavaScript frameworks.


    Now if you still want to use the map to render the html select tag via the iterator, you can use the following code.

    <select id="monthId" name="form.monthId">
      <s:iterator var="month" value="%{months}">
        <s:if test="month.value != 'May'">
          <option value="${month.key}" ${month.key == form.monthId?'selected="selected"':''}>
            <s:property value="%{month.value}"/>
          </option>
        </s:if>
       </s:iterator>
    </select>
    

    Note, that EL expressions used to pre-select the options should have access to valueStack variables due to Struts request wrapper. See How we use JSTL with the framework.