Search from Struts2 Library

Tuesday, September 16, 2008

doubleselect with full functionality

Struts 2 doubleselect

First this is a simple example of loading dynamic contents through doubleselect then the deficiencies of doubleselect are discussed and the way to overcome them

Simple Example

Struts 2 provides a fantastic doubleselect tag, which allows you to specify two HTML select lists in such a way that the contents of the second list is dependent on the selection of the first (1). About a month ago, I came across a situation where this type of relationship was very advantageous, and set off towards the relevant Struts 2 documentation to learn how this mysterious tag worked. I found the list of attributes useful, but the examples at the bottom of the page left much to be desired (they're completely hard-coded). In fact, even after a good hour of searching, I couldn't find a solid example of the doubleselect tag that didn't hard-code both lists! Obviously it's much more useful to take advantage of the java back-end, and it took me two full hours of trial and error to finally figure out how to get my particular scenario working. What follows is a detailed example showing how to use the Struts 2 doubleselect tag to its fullest, for the next time I or anyone else wishes to make good use of it.




For our example, suppose you run some sort of automotive website, and would like to let the use specify the Make and Model of a car. The list of Makes should contain the car company, like Porsche, Ferrari or Lamborghini. The lists of Models should be the specific cars those companies make, like "911 Turbo" and "Boxster S" for the Porsche, "F430 Spyder" and "FXX" for Ferrari, etc. So when Porsche is selected in the first list, it's set of models will be shown in the second list. If we change the selection in the first list to Ferrari, the second list should update to contain only the Ferrari models. We also want to know what Make and Model the user has selected, and be able to set default selections in each list. This can actually be done with very little JSP syntax using the doubleselect tag:

    <%@ taglib prefix="s" uri="/struts-tags"%>

<s:form action="selectCar" method="POST">
        <s:doubleselect
name="makeId"         doubleName="modelId"
list="allMakes"       doubleList="models"
listKey="id"          doubleListKey="id"
listValue="name"      doubleListValue="name"
value="defaultItem"   doubleValue="doubleDefaultItem" />
    </s:form>


Of course, in addition to the jsp shown above, we need a struts.xml file, the struts action, a Make class and a Model class. It is assumed that you already know how to set up the struts.xml file and the basics of the struts action. Here's what we need in the other files:
  • The struts action must contain a list of Makes - the car companies, like Porsche, Lamborghini and Ferrari - and properties called makeId and modelId (which should match the type of id in the Make class) and defaultItem and doubleDefaultItem (which should match the type of name in the Make class).
  • The Make class must have a name, an id and a list of Models - this is the set of cars made by each company, so things like "911 Turbo" and "Boxster S" would be in the Porsche's model list, but the Ferrari model list would contain different things like "F430 Spyder" and "FXX".
  • The Model class needs only a name and an id.
When the page loads, here is how the doubleselect tag is interpreted:
  • The list attribute will call getAllMakes in the struts action, and use that list as the primary list. Similarly, doubeList calls getModels on each Make, and uses the resulting lists as the secondary lists.
  • The listValue attribute will call getName on each entry in the primary list, and use the resulting list of names to show on screen in the first menu. Similarly, doubleListValue calls getName on each entry in the secondary list, and stores them in memory for showing in the second menu.
  • The value and doubleValue attributes will call getDefaultItem and getDoubleDefaultItem in the action, and use the results to pre-select entries in each list. For example, if you wanted the default Make to be Ferrari, you would make sure getDefaultItem returns the Ferrari object.
When the form is submitted, the name and doubleName attributes will call setMakeId and setModelId in the action, and give them the values of listKey and doubleListKey respectively. So if Lamborghini is selected in the first list, and Murcielago in the second, the parameters passed in setMakeId and setModelId would be the id of the Make instance which has the name Lamborghini, and the id of the Model instance which has the name Murcielago.

So that's all there is to it! I hope this has been helpful, and saves a bit of time for the next person trying to implement a complex double-list system with back-end support.


(1) This functionality is provided using javascript which is automatically generated when Struts interprets the doubleselect tag. One downside to this approach is that it will clutter up your source quite a bit if you're using a large dataset, but this is unavoidable while using this tag.

Known Issues:
Although doubleselect is a very good tag but there are some problems with it. You can not use any of doubleOnchange, doubleOnClick,doubleOndblclick etc till now. It is one of the known issues and can be resolved in the next release.
Solution:
Here is the solution to achieve double select full functionality and avoid even know issues. But there is a trade off you have to forget Ajax in that solution means here both list will be populated when page will load. Then you can you use this javascript to acheive the desired effect.

var appsTemp = document.campaign_form.eve;
appsRedirect(0);
function appsRedirect(x) {
var selected = false;
for (m = appsTemp.options.length - 1; m >= 0; m--) {
appsTemp.options[m] = null;
}

for (i = 0; i <> 0) && (! selected)) {
appsTemp.options[0].selected = true;
}
}

3 comments:

Unknown said...

could you share the action code because I don't understand where is the link between the both lists...

Unknown said...

Thanks for the detailed explanation, however, please could you explain how can you pass the modelId into the make class to fetch the respective makes of the model?

Anonymous said...

provide code instead of English words.