Search code examples
javaspringspring-bootcheckboxthymeleaf

How do I use the Checkbox with Java + Spring in Thymeleaf/HTML?


How do I receive either true or false from an checkbox in html with Thymeleaf over to my controller, so I can take the value either true or false and save in my DB. So far I receive these errors:

  1. org.thymeleaf.exceptions.TemplateInputException:
    An error happened during template parsing (template: "class path resource [templates/normal/start-dag.html]")
  2. Caused by: org.attoparser.ParseException:
    Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputCheckboxFieldTagProcessor' (template: "normal/start-dag" - line 24, col 44)
  3. Caused by: org.thymeleaf.exceptions.TemplateProcessingException:
    Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputCheckboxFieldTagProcessor' (template: "normal/start-dag" - line 24, col 44)
  4. 2018-07-17 09:05:16.097 ERROR 6713 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed;
    nested exception is org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/normal/start-dag.html]")] with root cause
  5. java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'goodNightOfSleep' available as request attribute
    at org.springframework.web.servlet.support.BindStatus.(BindStatus.java:153) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
    at org.springframework.web.servlet.support.RequestContext.getBindStatus(RequestContext.java:903) ~[spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]

My html looks like this:

<table>
    <tr>
        <input type="checkbox" th:path="goodNightOfSleep">
        <label th:for="${#ids.next('goodNightOfSleep')}" th:text="#{StartDay.goodNightOfSleep}">Kan du huske hvad du drømte?</label>
        <input type="checkbox" th:field="*{goodNightOfSleep}"/>
    </tr>
</table>

And my Controller:

// Start Day
@GetMapping("/normal/start-dag")
public  String opretGoal() {
    return "normal/start-dag";
}

@PostMapping("/normal/start-dag")
public String opretGoal(@ModelAttribute StartDay startDay, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "/normal/menu";
    }
    startDayService.createGoalOfTheDay(startDay);

    return "normal/menu";
}

My StartDay.java class:

@Entity
@Table(name = "start_day")
public class StartDay {

    @Id
    @Column(name = "age_in_days", nullable = true)
    private int ageInDays;
    @Column(name = "day_created", nullable = true)
    private String dayCreated;
    @Column(name = "username", nullable = true)
    private String username;
    @Column(name = "dream_remembered", nullable = true)
    private boolean dreamRemembered;
    @Column(name = "nightmare", nullable = true)
    private boolean nightmare;
    @Column(name = "waking_time", nullable = true)
    private int wakingTime;
    @Column(name = "good_night_of_sleep", nullable = true)
    private boolean goodNightOfSleep;

Any help appreciated :)

UPDATE #1

So I just tried to move the second th:field from the html, so it looks like this:

<table>
    <tr>
        <input type="checkbox" th:path="goodNightOfSleep">
        <label th:for="${#ids.next('goodNightOfSleep')}" th:text="#{StartDay.goodNightOfSleep}">Kan du huske hvad du drømte?</label>
    </tr>
</table>

And that makes me actually able to land on the page, but my checkbox looks like this, and doesn't return a value: enter image description here


Solution

  • Controller methods:

    @GetMapping("/normal/start-dag")
    public String opretGoal(Model model) {
        ...
        StartDay startDay = .... // e.g. new StartDay();
        model.addAttribute("startDay", startDay);
        ...
        return "normal/start-dag";
    }
    
    @PostMapping("/normal/start-dag")
    public String opretGoal(@Valid StartDay startDay, BindingResult bindingResult, Model model)
    {
        if (bindingResult.hasErrors()) {
            // log and/or handle errors
        }
        else {
            // your logic goes here
            startDayService.createGoalOfTheDay(startDay);
        }
        return "/normal/menu";
    }
    

    Template snippet:

    <form action="... or use th:action" method="post" th:object="${startDay}">
        ...
        <input type="checkbox" name="goodNightOfSleep">
        ...
    </form>
    

    You could also use th:field for the goodNightOfSleep-Input but it works like writen above. Thymeleaf match the field by name to the object defined in the form-element. If you check the box the value will be true else it will be false.

    The point is to 1.) add the object to the model and 2.) receive the object as a input parameter.

    Warning: The code is writen to the editor without testing it. Maybe there are typos.