I have problem in binding the list of objects contained inside a object on the form using thymeleaf

classic Classic list List threaded Threaded
22 messages Options
12
Reply | Threaded
Open this post in threaded view
|

I have problem in binding the list of objects contained inside a object on the form using thymeleaf

rajkumar
I have problem in binding the list of objects contained inside a object on the form using thymeleaf
I have following in controller,

        @RequestMapping(value="/edit",method=RequestMethod.GET)
        public ModelAndView getEditPage(
                        @RequestParam(value="id")Long userId,
                        Model model) throws IOException, SAXException
        {
                UserInfo userInfo = practiceService.getUserInfo(userId);
                EditCommand editCommand = mapper.map(userInfo, EditCommand.class);
                model.addAttribute(editCommand);
        return new ModelAndView("edit","userModel",model);
        }

I have following POJO class :

public class EditCommand {
        private Collection<UserAddress> userAddresses = new ArrayList<UserAddress>(); // list of address objects

I have follwing in edit.html page :

<!DOCTYPE html>
<section xmlns:th="http://www.thymeleaf.org">
<p th:inline="text">Edit Command Object : [[${editCommand}]]</p>
<form method="post" th:object="${editCommand}">

// removed rest of code to give show only error part
       
                <address th:each="userAddress : *{userAddresses}">
                        <input type="hidden" th:field="${userAddress.addressId}" />
                        <br/>
                        Address Type
                        <br/>
                        <label for="userStreet">Street : </label>
                        <input type="text" th:field="${userAddress.userStreet}" />
                        <br/>
                        <label for="userCity">City : </label>
                        <input type="text" th:field="${userAddress.userCity}" />
                        <br/>
                        <label for="userPincode">Pin Code : </label>
                        <input type="text" th:field="${userAddress.userPincode}" />
                        <br/>
                </address>

with the above code error is :

org.thymeleaf.exceptions.TemplateProcessingException: Expression "${userAddress.addressId}" is not valid: only selection variable expressions *{...} are allowed in field specifications

If i (replace '$' with '*') or (remove userAddress. before fields) in the above it says :

org.springframework.beans.NotReadablePropertyException: Invalid property 'userAddress'/(userid,usercity,userstreet,userpincode) of bean class [com.epro.web.EditCommand]: Bean property 'userAddress' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?



Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

danielfernandez
Administrator
Hi,

This is more a Spring EL binding issue than a Thymeleaf one. Using Spring EL in Spring MVC, you are not allowed to bind your form properties in a dynamic way like you are trying to do (by iterating them using an iteration "userAddress" variable).

You should instead bind your address objects directly using an array index as a part of your "th:field" expression. This is allowed by Spring EL:

<input type="text" th:field="*{userAddresses[0].userStreet}" />
...
<input type="text" th:field="*{userAddresses[1].userStreet}" />
...
<input type="text" th:field="*{userAddresses[2].userStreet}" />


Note that Spring MVC does not allow you to use a variable for that indexes (0,1,2...). So if you do not know the size of your "userAddresses" array beforehand, you can use Thymeleaf's expression preprocessing system (between "__") for applying a variable to your expression so that Spring MVC sees it as a literal index but it works for you:

<div th:each="userAddress, stat : *{userAddresses}">
   ...
   <input type="text" th:field="*{userAddresses[__${stat.index}__].userStreet}" />
   ...
</div>

Regards,
Daniel
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

rajkumar
thank you daniel
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

meyertee
In reply to this post by danielfernandez
Thank you both, I just had a very similar issue with using a dynamic map of form fields, and you saved me!
Using the preprocessor I'm now using strings to populate a map of fields:

<fieldset th:each="field:${allFields}">
  <label th:each="facet:${field.facets}"><input type="checkbox" th:field="*{fields[__${field.name}__]}" th:value="${facet.value}"/></label>
</fieldset>

The form backing bean simply has a map:
private Map<String, List<String>> fields;

Great stuff!
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

danielfernandez
Administrator
I'm glad it worked for both of you.

It would be nice to have an article on the website explaining this technique for creating dynamic web forms with Thymeleaf + Spring3...

Any of you (or any others) willing to write it? ;-)

Regards,
Daniel
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

felixiotg
In reply to this post by meyertee
This example help me too. Lot of thanks
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

Jad Bouchouka
In reply to this post by rajkumar
Why the binding works only with List,Map or an Array ?  Because I had a Set attribute in my bean but I get an exception. I cannot simply modify the Set by Collection, I cannot touch it. I think it's a SpringMVC issue. There's any other way to do it with Thymeleaf?
I just started working with Thymeleaf, so I'm new on it and I really like it, babay JSP/JSTL
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

Thibault Duchateau
In reply to this post by danielfernandez
Thanks! It works like a charm! :-)
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

sjacobs
This post was updated on .
In reply to this post by danielfernandez
I was able to follow this solution to display and modify a List of objects in an html table.

I have a scenario where I need to ADD A ROW (new Object) to an html table (or list of objects) and submit it via webflow to be persisted into a DB. So if the List had a size of (3) I want to submit back to the server a size of (4). Can I simply clone the last row in the table via javascript and increment the "stat.index" +1 for that row and submit this to the server? I tried doing this and I receive a strange behavior from webflow I receive back in my error obj the equivalent of:

evaluationException on fsList[3].sequenceNum
evaluationException on fsList[3].type
evaluationException on fsList[3].configId
evaluationException on fsList[3].comment  

Where '3' is the 4th index value that I generated via javascript.

I also tried to submit the new entry without an index value but I receive the same exceptions in the err obj.

evaluationException on fsList[].sequenceNum
evaluationException on fsList[].type
evaluationException on fsList[].configId
evaluationException on fsList[].comment

So my question is... how do I create a NEW entry to this list of objects and be able to submit and save it via html forms, thymeleaf, + Spring Webflow (or mvc)?

Note: I can modify existing List<Objects> that I pulled down save them... but I CANNOT create a new object and add it to the list. My current logic right now is to take the string that was generated by:

<input type="text" th:field="*{fsList[__${row.index}__].sequenceNum}" />

and either adding +1 to the index values or simply leaving the values blank. I even tried to remove the generated 'id' attribute and leaving only the 'name' attribute and that didn't work either...

<input type="text" id="fsList3.sequenceNum" name="fsList[3].sequenceNum" value="1.0" />
<input type="text" id="fsList.sequenceNum" name="fsList[].sequenceNum" value="1.0" />
<input type="text" name="fsList[].sequenceNum" value="1.0" />

-----------------------------------------------------------------------------
Edit... stepping into the webflow code the BindingModel contains the following:

org.springframework.webflow.mvc.view.BindingModel: 4 errors
Field error in object 'modelObj' on field 'fsList[3].sequenceNum': rejected value [null]; codes []; arguments []; default message [evaluationException on fsList[3].sequenceNum]
Field error in object 'modelObj' on field 'fsList[3].type': rejected value [null]; codes []; arguments []; default message [evaluationException on fsList[3].type]
Field error in object 'modelObj' on field 'fsList[3].configId': rejected value [null]; codes []; arguments []; default message [evaluationException on fList[3].configId]
Field error in object 'modelObj' on field 'fsList[3].comment': rejected value [null]; codes []; arguments []; default message [evaluationException on fsList[3].comment]

-----------------------------------------------------------------------------
This was the closest "solution" I found for this issue.

http://blog.richardadamdean.com/?p=12

Using an AutoPopulatingList. I actually couldn't get this to work for myself. I found this solution to be very unintuitive and hacky but... maybe it will help some one in the future as this issue is poorly documented.

Moreover, this isn't a Thymeleaf issue as I initially thought so posting here about it is probably not appropriate

Thanks,

S.J
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

Matt
In reply to this post by Jad Bouchouka
Sets do not have an accessor (.get(index)). They are unordered.
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

Alejandro Méndez
In reply to this post by danielfernandez
THANKS A LOT!


The tip of search for "Thymeleaf's expression preprocessing system" was I've ever been searching for (not only for this issue). I didn't know about preprocessing on Thymeleaf, now, thanks to you, i going to learn more about it and solve many other issues related on it.

Again. Than you
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

CarloLiwanag
Hi,

I am also facing the same problem, but only I am using a list of String. I have tried doing

<div th:each="val, stat : *{defaultTitles}">
  <p id="defaultTitles" name="defaultTitles" th:field="*{defaultTitles[__${stat.index}__]}"></p>
</div>

but the data gets lost once the form is submitted.

Please help.

Thanks,
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

CarloLiwanag
Please disregard. It works, I should have done an input element. :D
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

Phuoc
In reply to this post by danielfernandez
where is userAddresses?
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

                                                        </th:block>

The iteration works fine (when I take out the th:field or change it to a th:value that is). My goal is to read in a list of parameters and be able to edit the list on the page. The bug is probably right in front of me but I can't seem to see it. Any help is very much appreciated!

Wade
wade
In reply to this post by danielfernandez
Daniel, everything you write makes perfect sense, I just can't get it to work. I keep getting:

Invalid property 'ComfortableParameters[0].name' of bean class [admin.EditProfile]: Bean property 'ComfortableParameters[0].name' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

My Bean declares the List:
        private List<Parameter> ComfortableParameters;

My HTML template:
<th:block th:each="cparameter,ndx : *{ComfortableParameters}">                               
       
<input type="text" size="25" th:attr="value = ${cparameter.name}" th:field="*{ComfortableParameters[__${ndx.index}__].name}"/>
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

Metroids
Since it's seems the th:each is working, are you using you sure the "Parameter" object has
public String getName()
 and
public void setName(String name)
?

Everything looks correct to me.

As a side note, you shouldn't need

th:attr="value = ${cparameter.name}"

The th:field property should take care of that.
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

wade
You are my new hero!!

I forgot about accessors for the Parameter object as I just made the members public. I was just using it as a structure to group some simple data items. It never crossed my mind to add the accessors!

Thank you so much for your help!
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

zzheads
In reply to this post by danielfernandez
Trying to do very similar, doesnt work for me.
My template:

<li th:each="c, stat : ${project.collaborators}">
Developer
   <div class="custom-select">
     
      <select th:field="${t[__${stat.index}__]}">
         <option th:each="collaborator : ${allCollaborators}" th:value="${collaborator.name}" th:text="${collaborator.name}">Michael Pemulis</option>
      </select>
   </div>

Getting error: Neither BindingResult nor plain target object for bean name 't[0]' available as request attribute
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

Wade Schofield
It seems like the select should be <select th:field="*{c[__${stat.index}__]} or at least I don't know what "t" is.
Reply | Threaded
Open this post in threaded view
|

Re: I have problem in binding the list of objects contained inside a object on the form using thymeleaf

Wade Schofield
Oops typo:

<select th:field="*{project.collaborators[__${stat.index}__]}"

12