Search code examples
javascriptjavahtmlspringspring-form

How can I fix the initial state of a checkbox in a spring-form?


I'm using spring-boot with .jsp files to show web-content. My controller looks like this:

@Slf4j
@Controller
@AllArgsConstructor
@SessionAttributes({"language", "amount", "words"})
public class LanguageController
{
    private LanguageService languageService;

    // Additional services

    @Transactional
    @GetMapping("/language")
    public String editLanguage(ModelMap model, @RequestParam(value = "languageId", defaultValue = "-1", required = false) long languageId)
    {
        log.info("editLanguage() called");

        model.put("languageData", languageService.getLanguageData(languageId));

        return "language";
    }

    // Additional endpoints
}

And the .jsp file contains this:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<html>
<head>
    <%@include file="common/head.jspf" %>
</head>
<body>
<%@include file="common/navigation.jspf" %>
<div class="container">
    <h1>Edit Language Details</h1>
    <%--@elvariable id="languageData" type="io.fi0x.languagegenerator.logic.dto.LanguageData"--%>
    <form:form method="post" modelAttribute="languageData">
        <form:input type="hidden" path="id"/>
        <form:input type="hidden" path="username"/>
        <table>
            <tr>
                Name: <form:input type="text" path="name"/>
            </tr>
            <tr>
                    <%--        TODO: Fix the initial state of the checkbox to represent the language data--%>
                Public Language: <form:checkbox path="isPublic" checked="${languageData.isPublic}"/>
            </tr>
            <tr>
                Min-Word-Length: <form:input type="number" path="minWordLength"/>
            </tr>
            <tr>
                Max-Word-Length: <form:input type="number" path="maxWordLength"/>
            </tr>
            <tr>
                <a>Separate individual letter-combinations by ','</a>
            </tr>
            <tr>
                Possible Vocals: <form:input type="text" path="vocals"/>
            </tr>
            <tr>
                Possible Consonants: <form:input type="text" path="consonants"/>
            </tr>
            <tr>
                Possible Vocal-Consonant-Combinations: <form:input type="text" path="vocalConsonant"/>
            </tr>
            <tr>
                Possible Consonant-Vocal-Combinations: <form:input type="text" path="consonantVocals"/>
            </tr>
            <tr>
                Forbidden Combinations: <form:input type="text" path="forbiddenCombinations"/>
            </tr>
            <tr>
                <input type="submit" class="btn-success">
            </tr>
        </table>
    </form:form>
</div>
<%@include file="common/scripts.jspf" %>
</body>
</html>

When I open the endpoint in a browser, everything works, except for the isPublic checkbox. The checkbox is never pre-selected, weather the boolean is true or false.

I tried to access the value of the boolean in several ways, but none worked. What am I doing wrong here, why is the checked state always unchecked, regardless of the boolean-value?

I'm not trying to get the value of the checkbox, but I want to set the initial state of the checkbox.

Edit 1:

My LanguageData class:

@Data
@Builder
public class LanguageData
{
    private Long id;
    private String name;
    private String username;
    private Boolean isPublic;
    private int minWordLength;
    private int maxWordLength;

    private List<String> vocals;
    private List<String> consonants;
    private List<String> vocalConsonant;
    private List<String> consonantVocals;
    private List<String> forbiddenCombinations;

    public static LanguageData getFromEntity(Language language)
    {
        // Some conversion logic
    }

    public boolean invalid()
    {
        // Some logic
    }
}

Solution

  • I just found the solution:

    The first problem was actually that isPublic was a Boolean-object instead of a primitive-type. But this on its own does not make any visible changes.

    The second part of the problem, is the checked attribute in the <checkbox>-tag. This answer contains the solution:

    If the checked attribute exists, the checkbox will be checked regardless of what value you set it to.

    When I removed the checked attribute from the <checkbox>-tag, it finally worked. Here are the parts I changed, for anyone who finds this post in the future:

    LanguageData:

    @Data
    @Builder
    public class LanguageData
    {
        // Same as in question
    
        private boolean isPublic;
    
        // Same as in question
    }
    

    .jsp file:

            // Same as in question
    
                <tr>
                    Public Language: <form:checkbox path="isPublic" />
                </tr>
    
            // Same as in question