Checkbox values do not bind into object when false?

Hoàng Long picture Hoàng Long · Jan 4, 2012 · Viewed 26.4k times · Source

I used ModelAttribute to bind object in Spring web application.

Once I notice that, in case an object has an boolean value A is true, its value will not be updated if we uncheck A's checkbox.

For example, I have a Lesson object which has the attribute "active" = true. In "Edit Lesson" view, I make a checkbox which bind into "active". Things work well if the checkbox is checked (the binding object reflect the changes), but the object lesson will not change if we un-check the checkbox.

Further study tells me that's because the checkbox value may not get submitted by browser (this is an in-design of HTML). So I have to use the ugly request.getParameter to check if the value is set.

I just come by this question, and I see that asp.net mvc provide a way to work around it more elegantly. I think Spring must provide something similarly. Does anyone know how to do that?

Following is my code:

Controller code:

    @RequestMapping(value="/test", method = RequestMethod.POST)
    public String processEditLesson(@Valid Lesson lesson, BindingResult bindingResult, Model model) {
        System.out.println("Lesson is active: " + lesson.isActive()); // still "true" even if the checkbox is unset

        // Current work-around
        String isActive = request.getParameter("active");
        if (StringUtils.isNotNullOrEmpty(isActive)) {
            lesson.setActive(true);
        } else {
            lesson.setActive(false);
        }
        ...
    }

View code:

<form id="lesson" class="EditorForm" action="${rc.getContextUrl('/test.html')}" method="post" >

    <fieldset>
        <legend><@spring.message code="lesson.edit"/></legend>
        <@spring.formHiddenInput "lesson.id" />
        <@spring.formHiddenInput "lesson.studio.id" />

        <div class="Entry">
            <label for="name"><@spring.message code="lesson.message"/></label>
            <@spring.formInput "lesson.message" />
            <span class="ErrorMessage"><@spring.showErrors "<br/>" /></span>
        </div>

        <input type="checkbox" name="active" checked="checked" />
        <label for="active">${rc.getMessage('lesson.active')}</label>

        <input type="submit" value="<@spring.message code='common.update' />" />
    </fieldset>
</form>

Answer

Ralph picture Ralph · Jan 4, 2012

Spring has a built in workaround.

Simply add this additional hidden field to the form:

<input type="hidden" value="on" name="_active"/>

The parameter with a leading underscore is some kind of marker, to indicate the existence of a checkbox parameter with the same name, but without the underscore.

Spring should now set lesson.active to false if only _active=on is submitted.