Skip to content
Advertisement

Separate radio buttons which share the same th:field value (an array) with Thymeleaf?

I have a form where there are different groups of radio buttons. After using the Thymeleaf template I quickly faced an issue whereby I could not group my radio buttons due to them sharing the same th:fields tag. The issue is that I have a list to handle the ingredients, thus can not reference different fields for the th:fields tag (since there is only a single list). Thymeleaf then restricts my radio button options to one of all of the ingredient list items, even though I want to be able to select different radio options in various groups (buns, sauces, cheeses e.t.c.). Does anyone have a workaround for this? Here is my code:

HTML Template:

<form method="POST" th:object="${burger}">
        <div class="grid">

            <div class="ingredient-group" id="buns">
                <h3>Designate your bun:</h3>
                <div th:each="ingredient : ${bun}">
                    <input th:name="${ingredient.name}" type="radio" th:id="${ingredient.id}" th:value="${ingredient.id}" th:field="*{ingredients}" v-model="bun">
                    <label th:for="${ingredient.id}" th:text="${ingredient.name}">INGREDIENT</label>
                    <br>
                </div>
            </div>

            <div class="ingredient-group" id="meats">
                <h3>Pick your meat:</h3>
                <div th:each="ingredient : ${meat}">
                    <input th:name="${ingredient.name}" type="radio" th:id="${ingredient.id}" th:value="${ingredient.id}" th:field="*{ingredients}" v-model="meat">
                    <label th:for="${ingredient.id}" th:text="${ingredient.name}">INGREDIENT</label>
                    <br>
                </div>
            </div>

            <div class="ingredient-group" id="toppings">
                <h3>Choose your toppings:</h3>
                <div th:each="ingredient : ${topping}">
                    <input th:name="${ingredient.name}" type="checkbox" th:id="${ingredient.id}" th:value="${ingredient.id}" th:field="*{ingredients}" v-model="toppings">
                    <label th:for="${ingredient.id}" th:text="${ingredient.name}">INGREDIENT</label>
                    <br>
                </div>
            </div>

            <div class="ingredient-group" id="cheeses">
                <h3>Determine your cheese:</h3>
                <div th:each="ingredient : ${cheese}">
                    <input th:name="${ingredient.name}" type="radio" th:id="${ingredient.id}" th:value="${ingredient.id}" th:field="*{ingredients}" v-model="cheese">
                    <label th:for="${ingredient.id}" th:text="${ingredient.name}">INGREDIENT</label>
                    <br>
                </div>
            </div>

            <div class="ingredient-group" id="sauces">
                <h3>Select your sauce:</h3>
                <div th:each="ingredient : ${sauce}">
                    <input th:name="${ingredient.name}" type="radio" th:id="${ingredient.id}" th:value="${ingredient.id}" th:field="*{ingredients}" v-model="sauce">
                    <label th:for="${ingredient.id}" th:text="${ingredient.name}">INGREDIENT</label>
                    <br>
                </div>
            </div>
        </div>

        <div class="name-submit">
            <h3 class="submit-section-title row">Name your burger creation:</h3>
            <input class="submit-section-input" type="text" th:field="*{name}" v-model="burgerName"/>
            <br/>
            <button class="submit-section-button">Submit Your Burger</button>
        </div>
    </form>

Burger model that I refer to:

@Data
public class Burger {

    @NotNull
    @Size(min=5, message="Name must be at least 5 characters long")
    private String name;

    @NotNull
    @Size(min=1, message="You must choose at least 1 ingredient")
    private List<Ingredient> ingredients;
}

Advertisement

Answer

Some options:

  1. Use checkboxes instead, and use JavaScript to make sure they can only select one of each ingredient list. (Or use some kind of third party library w/selectable buttons so you still use checkboxes, but they don’t look like checkboxes.)

  2. Add a variable for each type of ingredient and add a helper method to turn them into a List<Ingredient>/. Then your radio buttons will works as normal, each bound to a different field. (Might have to remove null ingredients after, if they are optional.)

    public class Burger {
        Ingredient cheese;
        Ingredient sauce;
        Ingredient meat;
    
        public List<Ingredient> getIngredients() {
            return Arrays.asList(cheese, sauce, meat);
        }
    

I don’t think you’re going to get the functionality you want out of radio buttons, they just aren’t designed to be used that way.

9 People found this is helpful
Advertisement