aspose file tools*
The moose likes Struts and the fly likes checkbox list in struts 2 Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Frameworks » Struts
Bookmark "checkbox list in struts 2" Watch "checkbox list in struts 2" New topic
Author

checkbox list in struts 2

Jeff Ballie
Greenhorn

Joined: Jul 02, 2007
Posts: 12
Hi,

I'm hoping to get some ideas/technical suggestions on how to handle a task in struts 2.

Here's a brief overview of the functionality I need.... I have a table with a bunch of choices that should be expressed as a checkbox, and I want to keep track of which choices a User has selected. Modeled in a db, it looks like

Choices
- name

Users
- name

ChoicesUsers
name_id
user_id
selected

where selected is a boolean indicating whether a user has or has not selected the particular item (I've left out some obvious things like id's and so forth, since it's pretty standard... choices and Users are in N:1 relationships with the ChoicesUsers table - ie., many to many through ChoicesUsers)

So, I want to pass an object representing a choice and whether it was selected to a jsp, where I can display the choice name and put a checkmark if it was previously selected. If the user edits the choices, the form will submit, updates will be made to the db, and a new page will be rendered. So far, standard enough (I think).

One thing I really like about Struts2 is the convention that if I've named something choiceA in a page, I can have a getter/setter named getChoiceA() or setChoiceA(Boolean choice) and not have to deal with the request parameters directly. But unfortunately, I can't (easily) create on the fly methods called getChoiceA() (what do you think this is, rails? ;) )

I've struggled plenty with the checkboxlist tag, and while I've found lots of basic documentation by googling, I haven't been able to get much in the way of more how to tweak it to do something like this. Another thought was to use an iterator, which seems to work...



Though of course this puts me in a situation where I still either need to have a getter/setter for each choice name, or get parameters and parse the names (circumventing the whole get/set conventions that make Struts2 actions so useful, and creating pretty ugly code).

Another possibility would be to create an array of choices, but after hacking around, I wasn't able to get it to work. This would be the best solution - then I could have a getter/setter for an array (of booleans? strings would be easy enough to deal with as well). If anyone knows how to re-write the above so that I could just have a setChoices(ArrayList<Boolean> choices) method (or something similar), that would be really, really helpful.

Thanks to anyone who put in the time to read this far. Hey, if I'm approaching it all wrong and there's an easier way to do this, feel free to post your ideas!






Ankit Garg
Sheriff

Joined: Aug 03, 2008
Posts: 9303
    
  17

The easy solution for this according to me would be that in your action, you have a property like List<String> choices. Basically, I think you should render multiple checkboxes with the name of the choice as the value i.e. something like this

So what you need is a checkboxlist, which will take a list of all the choices with the values as the choice name. Now coming to the prepopulation. To prepopulate the checkbox list, you'll need another list, which will contain the choices that need to be selected in advance i.e. that need to be checked by default. So the action code would look like

In the JSP, I would render a checkboxlist as follows

Now in the next Action, you can get the userChoices as a List<String>, which will contain all the choices the user selected. Based on this you can set the ChoicesUsers table...


SCJP 6 | SCWCD 5 | Javaranch SCJP FAQ | SCWCD Links
Jeff Ballie
Greenhorn

Joined: Jul 02, 2007
Posts: 12
Thanks for the reply, Ankit.

Your solution would be effective for the checkboxlist tag... though I have to admit I'm a little disappointed to be splitting an object into several arraylists for the purpose of using a tag library. My first solution allowed me to just pass the object itself (the downside was that I couldn't read the results back in an array, which was leading to very cludgy code in the struts 2 action...)

I'd also prefer to avoid using the checkboxlist, because I want greater control over the formatting. I've read various methods to override this behavior and customize the formatting, but I need to control layout of checkboxlists on many different pages in different ways, which (I think) means I'd need to override the checkboxlist formatting five or six different times, with no real reuse outside of the page itself. So ultimately, I think it would be better to just do this in the page rather than overriding the tag...

Does anyone know how to modify the


So that it would return an array of choices?

Or, alternatively, how to modify (in the page itself)


So that it uses an iterator rather than the checkboxlist tag?

Thanks for the help.

Ankit Garg
Sheriff

Joined: Aug 03, 2008
Posts: 9303
    
  17

This thread is fun. I had to take my book in my hand and read a few things here and there

1. You don't need to split your List of choices. You can directly use the checkboxlist to use your List. I know that you might not use it, but still it will be good for your knowledge. So what you have is a List<ChoicesUsers> (name derived from your table name). The ChoicesUsers class has a property name (String) and checked (boolean). Now basically what you can do is create a checkboxlist using this list and provide a subset of this list as the value attribute so that some of the checkboxes are pre-selected. So you can do this

I'm not sure that the above code will work as this is the first time I'm using OGNL to get a subset of a List. So basically what we are doing is that we are creating a checkboxlist with the choices property of the action. listKey and listValue are used so that the value attribute of the generated checkbox and the text displayed for the checkbox are the name property of the ChoicesUsers class (as you did in your iterator example). The value attribute of checkboxlist is used to specify which options to pre-select. So from the choices list, we selected only those records whose checked property was true (using choices.{?#this.checked == true}), and then we created a list of only the name property of the remaining ChoicesUsers object (using .{name}). The action to which the data will be submitted can have a List<String> userChoices which will catch the list of checkboxes selected by the user. The list will contain the name of the choices selected by the user.

2. If you want to use iterator, then what you can do is use the name attribute as name="choice.%{#attr.item.name}" . The action to which this form will be submitted can have a Map<String> which will catch the names of the checkboxes selected by the user. This way the keys of the Map will contain the name of the choices selected by the user....
Jeff Ballie
Greenhorn

Joined: Jul 02, 2007
Posts: 12
Your checkbox solution definitely works. Just in case anyone else is following this thread... you can create a class



then have a struts 2 action class like this:



and then access this list in a jsp via


This works, though there's one minor downside - the resulting list will contain *only* those elements that have been selected. So if your form submission was
Choice A (checked)
Choice B (unchecked)
Choice C (checked)

The results of printing the list in setChoices() would be
Choice A
Choice C

which means that if choice B had been previously selected, and you'd persisted this somewhere, you need to keep track of what *isn't* in the list as well as what is... though that shouldn't be too big a problem, just a bit of extra programming.

(unfortunately, I wasn't able to convert this approach into an iterator that avoids using checkboxlist, and I couldn't find much documentation on the web on how to do this...)

It would be nice to set a map with choice names and a boolean for checked (or even just a list of Choices, ie., public void setChoices(List<Choice>) {}, though I don't think that's possible...

By the way, you *can* get a "map" with some hackery. If you name each field individually (and give up on getting an array) like this:


you can parse the names directly from the parameter list like this (in the struts 2 action class):




This has the advantage of providing a result for all the choices, rather than just listing the ones that were checked. If you've used Stuts 2 much, the disadvantages are pretty obvious (kludgy end-run around the conventions that make a struts 2 action class so useful and clean).













Ankit Garg
Sheriff

Joined: Aug 03, 2008
Posts: 9303
    
  17

Your checkbox solution definitely works.

Yay, it worked
By the way, you *can* get a "map" with some hackery. If you name each field individually (and give up on getting an array) like this:

you can parse the names directly from the parameter list like this (in the struts 2 action class):

There's no need for that. I showed you how you can get a Map of the selected checkboxes automatically. The name attribute should be name="choices.%{#attr.item.name}" (note the dot after choices) or name="choices['%{#attr.item.name}']" instead of name="choices%{#attr.item.name}". And checkboxes are meant to submit only selected values. You cannot alter that behavior. Only the selected checkboxes will be sent as a request parameter to the server.

PS: If the syntax name="choices['%{#attr.item.name}']" doesn't work, then try it without the single quotes i.e. name="choices[%{#attr.item.name}]"...
Jeff Ballie
Greenhorn

Joined: Jul 02, 2007
Posts: 12
Yeah, unfortunately I'm still a little confused about what kind of Map is returned from the code you provided (you mentioned a Map<String>, which would contain values selected by the user as the Keys... I'm assuming the keys map to whether the checkbox was selected? I did try to get this to work with a Map<String, Boolean> and a Map<String, Object>, but both gave me casting errors.

Anyway, if only the selected values are contained in the Map, then I don't think I'd get any advantages over a List (because the key would always map to true). The "Map" I was talking about with the kludge is a HashMap that has every field in the list as a key that maps to a "true" or "false" value... this way you would have full information about what was and wasn't selected (as you can see from my code, you actually don't get the hashmap, but you do get a true/false value associated with every element of the list.... I don't think this is any easier than just building a hashmap by iterating through the original list and mapping to true or false based on whether the name is contained in the values returned from the checkboxlist, and it's much kludgier, so I wouldn't recommend it either).

I may try to use the checkboxlist after all, since it seems to provide by far the cleanest solution - it was very easy to get that part working from your example, so the only issue is formatting, which seems pretty well documented (though I'll have to figure out how to implement it in different ways for different pages... if I get this working I'll post back).



Ankit Garg
Sheriff

Joined: Aug 03, 2008
Posts: 9303
    
  17

Jeff Ballie wrote:I did try to get this to work with a Map<String, Boolean> and a Map<String, Object>, but both gave me casting errors.

If you used this code for the iterator

And the property name in the action was choices, then Map<String, Boolean> should've worked. Of course still you'll only get the choices the user selected as the key and the value will always be true...
 
It is sorta covered in the JavaRanch Style Guide.
 
subject: checkbox list in struts 2