Search code examples
javaspringformsspring-bootthymeleaf

Why does this Spring Boot/Thymeleaf button hide my data or not work at all?


I'm curently trying to get into Spring Boot and Thymeleaf by following tutorials and playing around with the code they provide. I tried implementing an extra functionality and had the following problem: The code should display a ToDo-List consisting of ToDo-Objects that each have a name, description and a boolean status that denotes if they are done or not. Each line of the table is supposed to have a button to click in order to mark a ToDo as done.

<table style="border-collapse:collapse; font-family: Arial,Arial,sans-serif;">
    <tr>
        <th padding: 5px"></th>
        <th> To-Do</th>
        <th> Description</th>
        <th> Done?</th>
    </tr>
    <tr th:each="todo : ${todos}">


        <td>
            <!-- <form method="POST" th:action="@{/updateDone(exactToDo=${todo})}">
                <button type="submit" name="submit" value="value" class="link-button">Done</button>
            </form> -->

            <form method="POST" th:action="@{/updateDone}">
                <input type="hidden" name="exactToDo" id="exactToDo" th:value="${todo.getName()}" />
                <button type="submit" name="submit" value="value" class="link-button" >This is a link that sends a POST request</button>
            </form>
        </td>

        <td th:utext="${todo.name}" style="border: 1px solid black;">...</td>
        <td th:utext="${todo.description}" style="border: 1px solid black;">...</td>
        <td th:text="${todo.done} ? 'Yes! ' : 'No' " style="border: 1px solid black;">...</td>
    </tr>
</table>

Displaying the contents works, but my button does nothing in this configuration. I followed the directions from this older question, but it doesn't change the status of my ToDos. I can see in the Browser console that it sends a Post request, but there seems to be nothing inside. The part that is currently commented out makes the data disappear from my table, only leaving the first line with the headers. I tried various similar approaches that I found online, but they all had one of those two results.

Here is the code of the relevant controller:

    @RequestMapping(value = {"/updateDone"}, method=RequestMethod.POST)
public String completeTask(Model model, @RequestParam("exactToDo") String exactToDo){
    for (ToDo todo : todos){
        if (todo.getName().equals(exactToDo)){
            todo.markDone();
        }
    }
    return "list";
}

Setting return to "redirect:/list" fixes the problem with the "disappearing" data, but the status of the ToDo still doesn't change. I assume that the problem is that the ToDo object isn't sent to the method correctly, but I'm not exactly sure why. You might have noticed that I am trying to send todo.getName() instead of the ToDo Object directly, that is because when I try to send the object, I get an error in the second line of my posted Controller code, telling me that a String couldn't be converted into a ToDo-Object (the Controller was of course configured to take a ToDo object as parameter). This is why I think the problem has to be somewhere there.

I'd be very grateful if someone could help me fix this problem or point me to a better way of having a button on an HTML-page activate a method in my Java-Code. Tips for good learning resources are also greatly appreciated. I'm trying to learn Spring and Thymeleaf in order to make User Interfaces for Java programs.

Thank you for your time!


Solution

  • First thing First.

    Why would you need to write so much (form) just for a button? Now if you "must" use form then you are missing the th:object="${todo}" in your form tag. It will help Controller to understand on what object you are going to take some action.

    But I would suggest you use this inside your 'td' block instead of a form. It will do the same job for you. Once your request is successful, you can redirect it to your list and you should see the new results getting reflected immediately.

     <a href="/updateDone" th:href="@{/updateDone}">Mark Done</a>
    

    You can refer this to see a full blown example. Here you will find two things. User Controller and Task Controller that might interest you.