Tuesday, 28 September 2004

HTML labels in struts multibox

I'm blogging about this in the hope that this will help other people and save them the time that I have wasted tracking this down.

Like I have blogged about before, using labels in html forms is a good thing. It makes the form easier to use, and over all is much nicer. I think that this is especially true for checkboxes and radio buttons.

Now, we are using struts for our app, and as recomended we are using a multibox to manage a group of related check boxes. Now the trouble is that I could not figure out how to add a html label. The spec says that you don't have to use the "for" attribute, but I found that it didn't seem to work this way in IE (works in Firefox of course). And the example that everyone points to didn't use labels.

Now, using the example, for it to work I had to add in a cast and use some java code (not tags!) to get it to work. Here is the modified example:
<logic:iterate id="item" property="items">
<label for="selectedItems.<bean:write name="item" property="label"/>">
<html:multibox property="selectedItems"
styleId='<%="selectedItems." + ((org.apache.struts.util.LabelValueBean)item).getLabel()%>'>
<bean:write name="item" property="value"/>
</html:multibox>
<bean:write name="item" property="label"/>
</label>
</logic:iterate>


The changes are the styleId and the label tags. Not the best experience, but I hope that this will save someone else the time that it has cost me.
Update: I changed the id to point to the label and not the value. The label is more likely to be unique on the page. My bad.
Update 2: I made the changes that I mentioned in the post to ensure that the label is unique in the form. ;-)

12 comments:

  1. One thing that I thought of, you would probably want your label unique in the whole form, so it's probably not the best to just tie it to the text in the check box (like if you had two sets of check boxes with "N/A").
    So, it's better to tie in the property ("selectedItems" in this case) as well. I'll change the posted example when I can try it out and make sure that it works.

    ReplyDelete
  2. Thanks for the tip, it got me on the right track.
    One possible change is to use the indexId property
    of the iterate tag to simplify the naming and not
    worry about any funky characters in the labels.
    Just substitute some logical name for the control
    for "xx" in the snippet below. This also removes
    the need for the cast.
    <logic:iterate id="item" property="items"
    indexId="count">
    <label for="xx<bean:write name='count'/>">
    <bean:write name="item" property="label"/>
    </label>
    <html:multibox property="item"
    styleId="<%="xx"+count%>">
    <bean:write name="item" property="value"/>
    </html:multibox>
    </logic:iterate>

    ReplyDelete
  3. That is an excellent point Mike. I never liked the cast at all.

    ReplyDelete
  4. Pls send m the detail example of
    with iterator ,which briefs the multiple check boxes with dropdown list

    ReplyDelete
  5. Vikas, just look at Mike's post for a detailed example of using multiple check boxes.
    The only thing that you would have to do is load the correct collection into the jsp.
    As for using a dropdown list, if you load your info into a LabelValueBean you can just display them with the <html:options> tag. ;-)
    http://struts.apache.org/api/org/apache/struts/util/LabelValueBean.html

    ReplyDelete
  6. Rajasekhar Cherukuri8 July 2005 at 12:02

    Hi,
    A very good example on indexId attribute of logic:iterate. Thanks a lot...

    ReplyDelete
  7. I am currently struggling to include the HTML:MULTIBOX code into a JSP file.
    without the tag I can successfully get both the label and the value of the LabelValueBean created.
    as soon as it is there, I get a nasty
    "Cannot find bean under name org.apache.struts.taglib.html.BEAN"
    Any ideas?
    Thank you

    ReplyDelete
  8. Ya, I hate that error. I usually find that's when I am calling something with the property tag or the "name" tag when I should be using the other.
    If you still can't figure it out, post the code you've got trouble with and I can see what I can do. ;-)

    ReplyDelete
  9. First, thank you for the fast reply!
    This is the code in my JSP file, which works:
    <td>
    <logic:iterate name="CourseReportForm"
    id="annumOption" property="annumOptions" >
    <bean:write name="annumOption"
    property="label"/>
    <bean:write name="annumOption"
    property="value"/><br>
    </logic:iterate>
    </td>
    As soon as it is changed to:
    <td>
    <logic:iterate name="CourseReportForm"
    id="annumOption" property="annumOptions" >
    <html:multibox property="selectedAnnums">
    <bean:write name="annumOption"
    property="label"/>
    </html:multibox>
    <bean:write name="annumOption"
    property="value"/><br>
    </logic:iterate>
    </td>
    it replies (upon runtime) with a
    javax.servlet.ServletException: Cannot find bean under name org.apache.struts.taglib.html.BEAN
    I am using:
    <%@taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
    <%@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%>
    <%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
    The CourseReportForm has a getter method for selectedAnnums.
    Thank you.

    ReplyDelete
  10. Hi again.
    I would like to finally share the solution to my html:multibox problem...
    here it is:
    <logic:iterate name="CourseReportForm" id="annumOption" property="annumOptions" >
    <html:form action="courseReport.do"> &lt!-- THIS IS IMPORTANT -->
    <html:multibox property="selectedAnnums">
    <bean:write name="annumOption" property="label"/>
    </html:multibox>
    </html:form>
    <bean:write name="annumOption" property="value"/><br>
    </logic:iterate>
    Action courseReport.do should be present in struts-config.jsp, as:
    <global-forwards>
    ...
    <forward name="courseReport" path="/courseReport.do"/>
    </global-forwards>
    AND (again in struts-config.xml)
    <action-mappings>
    ...
    <action
    path="/courseReport"
    type="uk.ac.port.viewpoint.control.CourseReportAction"
    name="CourseReportForm"
    scope="request">
    <forward name="success" path="/courseReport.jsp"/>
    </action>
    </action-mappings>
    Hope you find it useful!

    ReplyDelete
  11. Yes, you'd have to make sure that the multibox is contained within a form. ;-)
    I'd move the form defination OUT of the iterate loop though... it would make more sense when you're reading the html.
    I don't understand why you'd put the forward as a global forward... are you accessing it from different action classes? If you're just calling it from the CourseReportAction class then the local forward defination should be enough.
    All the best. ;-)

    ReplyDelete
  12. The reason I am doing that is because I associate this action with an from a previous jsp.

    ReplyDelete