Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thymeleaf nested object form binding not generating good input name

I have a following object structure:

public class A{

    private int id;
    private B objB;

    public A(){}

    --- setters & getters ---
}

This is my class B:

public class B{

    private int id;
    private int test;

    public B(){}

    --- setters & getters ---
}

Im passing an A object to my view and i want to create a form to my B object:

<form id="bForm" th:object=${A.objB} th:action="@{/save}">
    <input th:field=*{test} type="text"/>
</form>

However the above code will work it will generate the input name like this: objB.test and for this my controller cannot bind it to a B object.

This is the receiving method in my controller:

    @RequestMapping("/save")
    @ResponseBody
    public String setB(@ModelAttribute("bForm") B b, BindingResult result) {
        aService.setB(b);
        return "...";
    }

How can i set Thymeleaf to name my fields without the prefix so instead of: objB.test just test?

Any help is greatly appreciated.

like image 767
Wermerb Avatar asked Jun 22 '26 13:06

Wermerb


2 Answers

According to thymeleaf-spring docs:

Values for th:object attributes in form tags must be variable expressions (${...}) specifying only the name of a model attribute, without property navigation. This means that an expression like ${seedStarter} is valid, but ${seedStarter.data} would not be.

Try using a th:with attribute before your form to assign your A.objB variable and, therefore, avoid using property navigation in the th:object attribute.

It seems that to adhere to this requirement you have to set an additional model attribute in your Spring controller's handler method that is handling the initial form rendering. So given that you already have something like this in some part of your code:

model.addAttribute("A", new A());

add another line:

model.addAttribute("bForm", new B());

Keep in mind to keep the model attribute name consistent with the one you had set in @ModelAttribute annotation in your submission request handler you've posted in your question.

like image 152
Michal M Avatar answered Jun 24 '26 08:06

Michal M


Maybe a late answer, but if objectB is inner object of A, then you can bind fields to B as inner object of A and process objectA in your controller.

It would look something like this, but in my case prompt is Arraylist of contained objects here:

    <th:block th:each="pr, stat : ${taskExecution.prompt}">
      <input type="hidden" id="hiddenName" th:field="*{prompt[__${stat.index}__].name}" th:value="${pr.name}">
      <input type="hidden" id="hiddenValue" th:field="*{prompt[__${stat.index}__].value}" th:value="${pr.value}">
    </th:block>
like image 31
McAnder Avatar answered Jun 24 '26 09:06

McAnder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!