PDA

View Full Version : binding collections


sherihan
Jan 27th, 2005, 02:07 AM
Hi,
I want to create a form which contains a button.
Whenever I click this button a new row should be added in a table so that the user could enter a new item.
On submitting this form I want to bind all the data entered in the table.
How could I do this?
Could anyone help me in this?
Thanks in Advance.
Sherihan.

radone
Jan 27th, 2005, 04:11 AM
This should be probably Javascript issue.

In short - how do I thing it should be created:
On button click you will add a row with <input> items. (their names must be unique in form)
On button click you will increment <input type="hidden"> field as a counter.
On submit you will get "hidden" field - as a counter and fields - for each row you have to do the action.[/code][/quote][/i]

sherihan
Jan 27th, 2005, 05:35 AM
Hi,
Thanks for replying.
But the main problem is how could i make the binding.
Suppose the table is hard coded ( the items are not added dynamically), how could i make the binding.
Would u plz sensd me a sample of the jsp.
Thanks in Advance.
Sherihan.

Christian
Jan 27th, 2005, 08:41 AM
Hi,
here is how I solved this problem:
I have a session object named "data" that has a property object named "subscriber".
A subscriber can have one or more Phonenumbers (implemented as a
java.util.List of PhoneNumbers).
Phonenumbers are represented by a PhoneNumber class with 2 properties: number and type.

I hava a "Add number" button in my form. If the user hits this button,
a SimpleFormController is called and a new empty PhoneNumber object
ist added to the List of the Command object (data.subscriber.phoneNumbers). Then the same form is dispalyed again
via "return (showForm(req, resp, errors));"

The binding of the whole list is done with the aid of the varStatus property
of the c:forEach loop. Spring's bind tag treats indexed properties
(Arrays and List as far as I know) equally. You access an entry in the PhoneNumber list the same way as if you would access an array entry.
Note that you must use the "status.expression" for the name of the input field in order to make this work.

<c:forEach varStatus="loop" items="${data.subscriber.phoneNumbers}">
<tr>
<td>Phonenumber:</td>
<td>
<spring:bind path="data.subscriber.phoneNumbers[${loop.index}].number">

<input type="text" name="<c:out value="${status.expression}" />" value="<c:out value="${status.value}"/>">

</spring:bind>
</td>

<td>Type:</td>
<td>

<spring:bind path="data.subscriber.phoneNumbers[${loop.index}].type">
<input type="text" name="<c:out value="${status.expression}" />" value="<c:out value="${status.value}"/>">
</spring:bind>

</td>
</tr>
</c:forEach>

hth ,
Chris

huijzer
Jan 27th, 2005, 09:44 AM
Chris,

I am very interested in your solution. Especially since it does not seem to rely on JavaScript. Is it possible to post the code of your Controller?

Thanks in advance!

Arjan Huijzer

Christian
Feb 1st, 2005, 07:52 AM
Sorry for my late answer, I am very busy in the moment
My Controller looks like this:

public class MyFormController extends SimpleFormController {

protected ModelAndView onSubmit(HttpServletRequest req,
HttpServletResponse resp, Object command, BindException errors)
throws Exception {
SessionData data = (SessionData) command;


//determine which button was pressed
if (req.getParameter("button1") != null) {
//do something in method_1
}
else if (req.getParameter("button2") != null) {
//do something diffrent in method_2
}
else {
//do something even more diffrent in method_3
}



return (showForm(req, resp, errors));
}

You can also use a MultiActionController to determine wich button was pressed, but i like onSubmit method, because it supplies you with the command object. There are also some custom SimpleFormController that can be used like MultiActionControllers posted in the forum, just search for it if u like to give them a try.

HtH, Chris

Christian
Feb 1st, 2005, 08:01 AM
To make a connection to my first post on this topic, if you want to add a new PhoneNumber TextField to your HTML form, do something like this
in one of the methods that are called in the if...else part of the Controller:


note: the <property name="sessionForm"><value>true<value><property> must be set to true in order to work with your command object this way (never tried it without it, but I don't think it would work)

//add new empty Phonenumber
data.getSubscriber().getPhoneNumbers().add(new PhoneNumber("",""));

When the form is displayed again, a new empty TextField will be created.
Note that you might want to check if a PhoneNumber contains only empty fields when you save the form in a database or if you do something else with the form data.

huijzer
Feb 1st, 2005, 08:39 AM
Thanks!

sherihan
Feb 2nd, 2005, 06:04 AM
Hi Christian,
Thanks a lot for you reply.
I just have one more question.
Does your solution work only with lists and arrays?
What about sets? Do they cause any problem?
I got the following error after trying to a new itemLine to my invoice form:

org.springframework.beans.InvalidPropertyException : Invalid property 'itemLines[0]' of bean class [com._4s_.invoice.model.Invoice]: Property referenced in indexed property path 'itemLines[0]' is neither an array nor a List nor a Map; returned value was [3]

Do u have any idea why does this happen?

Thanks in Advance.

lor
Jun 7th, 2006, 12:47 PM
Hi, I've an error with the ${loop.index}. A numberFormatException because the expression isn't evaluated.

I've found a solution : put the index in the resquet and increase it at each loop but it's not as smart as your solution.

Does anyone know why ${loop.index} isn't evaluated?

Laure


<c:forEach varStatus="loop" items="${data.subscriber.phoneNumbers}">
<tr>
<td>Phonenumber:</td>
<td>
<spring:bind path="data.subscriber.phoneNumbers[${loop.index}].number">

<input type="text" name="<c:out value="${status.expression}" />" value="<c:out value="${status.value}"/>">

</spring:bind>
</c:forEach>

hth ,
Chris

lor
Jun 7th, 2006, 12:58 PM
Oups, I'm sorry.

I've made a mistake in my foreach tag :

<c:forEach var="loop" items="${data.subscriber.phoneNumbers}">

instead of

<c:forEach varStatus="loop" items="${data.subscriber.phoneNumbers}">

I'm confused.

Laure

Hi, I've an error with the ${loop.index}. A numberFormatException because the expression isn't evaluated.

I've found a solution : put the index in the resquet and increase it at each loop but it's not as smart as your solution.

Does anyone know why ${loop.index} isn't evaluated?

Laure

bahaw
Jun 14th, 2006, 12:28 PM
Folks,

My problem is a continuation of this. Maybe you'd encounter this as you go along.

To solve adding new rows, I've implemented some code in the onSubmit(...) methods (or referenceData(.)). The new rows are being added successfully.

But I have two more problems (I have solved one of these at the time of this writing).

FIXED:
1. When I referesh the page, new unnecessary rows would be added. I have fixed this by checking if the last object added in the list is empty.

NOT FIXED:
2. When I delete a row (via a checkbox which I have implemented also), the page is loaded with the row I selected previously removed. But when I refresh the page, I get a dirty InvalidPropertyException - How do I fix this? It seems that the command object in session still thinks it has that index w/c I just deleted.

arshad_nj
Sep 21st, 2006, 04:42 PM
Hey Guys,

Having same issues with List binding and I get this exception intermittently:

2006-09-21 16:21:25,564 ERROR [org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/dev].[]] - <Servlet.service() for servlet donorschoose threw exception>
org.springframework.beans.InvalidPropertyException : Invalid property 'alternateResources[0]' of bean class [xxx.vo.ScreenProposalMaterialVO]: Index of out of bounds in property path 'alternateResources[0]'; nested exception is java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:546)
at java.util.ArrayList.get(ArrayList.java:321)
and here is my code:
<c:forEach var="resourceEntry" items="${command.alternateResources}" varStatus="lineInfo">
<td align="left"><b>price:</b>
<td>$
<spring:bind path="command.alternateResources[${lineInfo.index}].price">
<input size=7 value="${status.value}" name="${status.expression}"/>
</spring:bind>
</c:forEach>

klasgermunder
Nov 1st, 2006, 12:10 PM
i have the code loking like the one below an i want to place all contries in two diffrent dropdown menues.

the problem i have is when i submit the form the countries list has the ids from the Countries object.

how do i submit the "Countries object" instead?

This is just an example madeup right now but its concept iam looking for.

jsp code

<select name="countries">
<c:forEach var="country" items="${status.value}">
<option value="<c:out value='${country.id}'/>">
<c:out value='${country.sCountryName}'/>
</option>
</c:forEach>
</select>

------------------------
public class Company{
Arraylist countries;

........
-------------------------
public class Countries{

protected String sCountryName;
protected int id;
.................

ironbeast
Dec 22nd, 2006, 10:36 AM
Christian, can you post your model object code as well? I am trying to do something similar, except I am trying to bind arbitrary number of rows, each with radio buttons (accept/reject) and submit them all at once. So, multiple rows will be updated on my database instead of individual ones as present.