This week's book giveaway is in the OCMJEA forum.
We're giving away four copies of OCM Java EE 6 Enterprise Architect Exam Guide and have Paul Allen & Joseph Bambara on-line!
See this thread for details.
The moose likes Struts and the fly likes dynamic form elements using struts Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of OCM Java EE 6 Enterprise Architect Exam Guide this week in the OCMJEA forum!
JavaRanch » Java Forums » Frameworks » Struts
Bookmark "dynamic form elements using struts" Watch "dynamic form elements using struts" New topic
Author

dynamic form elements using struts

Naresh Chaurasia
Ranch Hand

Joined: May 18, 2005
Posts: 356
Hi,
I have a form in which there is option for adding a row (row is textbox and other widgets) by clicking on button.

In a scenario like this, how will i make use of ActionForm's validate method to do the validation of all the elements in my form, since the elemets in the form are changing.

thnx in advance


SCJP 1.4, SCWCD1.4, OCA(1Z0-007)
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
For something like this, I'd recommend that you represent a single row as a JavaBean representing what is in the row (for example, Customer, LoanApplication, etc. -- whatever the row represents) and then have a List of these objects in your ActionForm.

You would then want to use indexed properties to reference them in your JSP. Since the list could expand, you'd want to use some sort of lazy-initialization logic in the getters of your ActionForm to make sure that the List is always large enough. This link explains some techniques for doing this.

Then, in your validate() method, you simply have to iterate through the elements of the List and validate each one.


Merrill
Consultant, Sima Solutions
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Hi,

Could you be more specific. Like how would you go about storing the row in a Bean let's say. Could you elaborate more by providing a simple example ?

Thanks,
Pia
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
Say you have a page that displays a list of employees and allows you to change the status of any employee in the list. Here's what you'd code:

EmployeeListForm ActionForm

employeeList.jsp


Read the links I gave you and you'll understand how this code works.
[ July 31, 2006: Message edited by: Merrill Higginson ]
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Hi,

Thanks for the example. I have another question. I have a button which will add a new row to the existing data. My question is: how will I keep track of the index in this case ? From what I see to use the indexed property one has to enclose the fields in "<logic:iterate>" tags but I'm not sure how this would work if I add rows dynamically.

Thanks for the explanation
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
When the page is displayed, you know how large the list is. You can get this value with:

<bean:size id="employeeListSize" name="myForm" property="employees" />

Then, in your Javascript code that adds rows, you can increment that number to calcluate what your next index should be.

example:


If you read the links I gave you, you will understand the notation used for the indexed property. "employee[0].status" refers to the status of the first employee, "employee[1].status" to the status of the second employee, etc. The <html:text indexed="true" /> does the correct naming automatically, but in your JavaScript, you have to do the indexed naming yourself.
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
OK Merrill,

Following you even more now. But.....
'
I have this Javascript function which is getting size of the list. Here it is:


The alert box comes back with value of undefined. Is there a way I can go about fixing this ?

However
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Can I use a scriptlet to get the ActionForm from the request object in order to get at the list property and therefore get the list size ?

Do you know a better way of doing this other than the above. That is the only thing I can think of at the moment.
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
Sorry. The code I gave you is incorrect. It should read:

// this is a global variable that contains the current size of the listvar
<bean:size id="employeeListSize" name="myForm" property="employees" />
g_employeeSize = <bean:write name="employeeListSize" />;

Note: g_employeeSize must be a global variable, so you do not want to define it inside a function. You can increment it in a function if you want, but don't define it inside a function.
[ July 31, 2006: Message edited by: Merrill Higginson ]
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Ok Merrill,

One more issue and I think I should be done with this. Thanks so much for your help. I believe I understand how this things works now. But.... I have an issue.

Here's my ActionForm for my Application



PPOEntry Class consists of the following:


private String pPOName;
private Date startDate;
private Date endDate;

with the necessary getters and setters.

Now in my Javascript, I am now able to get the size of the list ok. But....
I'm still having a little difficulty. Well 2 problems really.

1. if I say :


and then do the following:



I get the error:

java.lang.IllegalArgumentException: Invalid indexed property 'ppoentry[' + newPPOsize + ']'


but if I do this :



it works..... Not sure why this is....

2. Going further - the 2nd issue

If the above works - I can't seem to do the following:

<html:select styleClass="tabletitle4" name="ppolistform" property="ppoentry[0]".pPOName> to get at the pPOName attribute of PPOEntry. I get an error stating the following:

javax.servlet.jsp.JspException: No getter method available for property ppoentry
[0].pPOName for bean under name ppolistform
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
In your first post, you mentioned that you would be adding a row by clicking on a button. I had always assumed that you would be doing this through JavaScript using the InnerHtml technique described in this link. My assumption has been that you have an existing set of rows that you would display using the <logic:iterate> technique that I demonstrated above, and that if the user clicks the "add row" button, you would use JavaScript to add the row. If that is the case, there are a couple of things you need to understand:

1-When using JavaScript, you deal only with regular HTML tags, not Struts tags. Struts tags are a server-side technology. JavaScript is a client-side technology, and it only understands plain HTML.

2. If you create an <input> tags, Struts can still work with them once the form is submitted so long as the name attribute of the tag matches what you would have put as the property attribute on a struts tag. So, instead of <html:submit property="xyz" /> you need to write <submit name="xyz">.

3. With this technique, you add a row and some cells to the table using DOM methods, you create the HTML as a JavaScript String, and then assign it to the InnerHTML property of a cell.

Given these facts, see if you can figure out how to do this for your specific example.
[ August 01, 2006: Message edited by: Merrill Higginson ]
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Merrill,

I know about the use of the "innerHTML" tag. In fact, this is my function:




and it works in that new rows are in fact added.

My function to insert a "Select" tag is the following:


And this works !!!. It appears that the Struts tags are just stripped/replaced by normal HTML Tags. My problem is that for some reason when I try to concatenate the index to insert with the rest of the array as in ppoEntry[' + index + ']' it doesn't like this, but if I hardcode ppoEntry[0] it takes it.

Secondly,it can't seem to understand ppoEntry[index].pPOName - it understands up to ppoEntry[index] but then complains about the error I indicated in my last post.

Clarification needed. OK with the first few rows which aren't added with the button, these are created with logic:iterate tags but they represent elements in a different list. I want to add new row items to a new list, which will then populate some database tables in the backend.

Ok first things first... Do you know why I'm getting the first error mentioned above. At first I thought that the size attribute was probably misinterpreted because it's a number instead of a string but no such luck.
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Ok Can you help me with my first question concerning the problem with using the size variable and concatenating it to the rest of the object name

Please Merrill, I'm really close to figuring this out. Just a bit more guidance
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
The first problem is due to improperly concatenating variables in JavaScript.

The second problem is due to non-standard capitalization in your ActionForm bean. Getter and setter methods must meet the JavaBean naming standard, and yours don't.

As for the rest of it, I've already told you why it's a bad idea to try and use Struts tags in innerHTML, and you refuse to believe me. In that case, there's not much I can do to help you.
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Ok.


What's wrong with my concatentation ?

Java Bean naming conventions I thought were obeyed. If my instance variable is ppoName, then the getter/setter should be get/set PpoName where you capitalize on the first letter.

I really appreciate your help thus far, but there's no reason to behave that way. But whatever
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
Pia,

I apologize for being abrupt. I don't mean to offend you, but I've spent a lot of time trying to help you, and it's very frustrating when you completely ignore what I tell you. The point I am trying to make to you is that you are headed down the wrong path by trying to mix Stuts tags and innerHTML. If you want to pursue that path, that's fine, but I'm not going to be able to advise you on it.

What's wrong with my concatentation ?


You haven't shown me how you tried to concatenate the index with the rest of the property name. All I know is that it's clear from this message:

java.lang.IllegalArgumentException: Invalid indexed property 'ppoentry[' + newPPOsize + ']'

That Struts didn't recognize the concatenation. If you'll show me the code you used to concatenate it, I may be able to help you identify what's wrong.

Regarding your ActionForm bean: I'd advise renaming the property pPOName to ppoName and making sure the getter is getPpoName().
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
Ok, I've taken a second look at your code, and here's what I've come up with.

The reason this appears to work up to a point is that your <html:select> and <htmlption> tags are actually being interpreted on the server-side and exchanged for regular HTML code. That's fine, except that you have to be very clear about what is happening on the server-side and what is happening on the client-side. In the following statement:

selectBox = selectBox + '<html:select styleClass="tabletitle4" name="ppolistform" property="ppoentry[0]">';

What is happening is that on the server-side, the <html:select> tag is being rendered into an HTML <select> tag. If you use your browser's "display source" funciton, you will see that the statement reads:

selectBox = selectBox + '<select class="tabletitle4" name="ppoentry[0]">';

You will also see that this:

selectBox = selectBox + '<logic:iterate id="result" name="ppolistform" property="allAvailablePPOs">';

gets translated to this:

selectBox = selectBox + '';

That's fine if you want to do it that way, but you have to realize that everything inside any Struts tag is being evaluated on the server-side and translated. You therefore can't put a javascript (client-side) variable inside a Struts tag. It's much simpler if you just use a regular HTML tag. That way you know the tag is not being manipulated on the server-side and you can manipulate it yourself.

Here's the code I would write for this:



I'm mixing Struts tags with JavaScript here, but it's very clear in my mind what will end up in the generated code and what will not. The <logic:iterate> tag, for example, will not show up in the generated code, but will help me generate the desired code. When you're doing this mixture, you always need to use the "view source" function to see what actually got generated. That will help you debug it.

Did that help?
[ August 01, 2006: Message edited by: Merrill Higginson ]
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Hi Merrill,

Thanks for the apology. I did get what you were saying concerning the Struts tags etc. and removed them before your last post. Your idea concerning removing the logic tags from the innerHTML is a good one.

Another thing is..... on trying to submit my form with the one new row added. I do the following in my Action just to see if things are being added to the Form Bean:

Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Hi Merrill,

Thanks for the apology. I did get what you were saying concerning the Struts tags etc. and removed them before your last post. Your idea concerning removing the logic tags from the innerHTML is a good one.

Another thing is..... on trying to submit my form with the one new row added. I do the following in my Action just to see if things are being added to the Form Bean:



he size prints out correctly with a value of one. However the ppoID corresponding to the value in the select tag is "null". Do you know what I'm missing here.
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Hi Merrill,


Good news, the other two fields excepting the ppoID one which I mentioned is returning a null. Just need to get this value to update.
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
Show me the code that generates your <select> tag. That's probably where the problem lies.
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
<logic resent name="ppolistform" property="allAvailablePPOs">;
var selectBox = '<select class="tabletitle4" name="ppoentry['+newPPOsize+'].ppoID>';
<logic:iterate id="result" name="ppolistform" property="allAvailablePPOs">;
<bean efine id="ppoName" name="result" property="name"/>;
<bean efine id="ppoId" name="result" property="ppoId"/>;
var ppoID = <bean:write name="ppoId"/>;
selectBox += '<option value='+ ppoID + '><bean:write name="result" property="name"/></option>';
</logic:iterate></logic resent>
selectBox += '</select>';
return selectBox;
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Merrill,

Never mind... I think I got it to work. There was a problem in my ActionForm. But it's good now
Pia Pringle
Greenhorn

Joined: Jun 05, 2006
Posts: 21
Merrill,

Thank you so much for your guidance. I really appreciate it !! I finally got the behaviour I was looking for. I have another question for you.

I am using an onblur event to validate one of my date fields and I also have this image next to it, that when clicked pops up a calendar from where the user can choose a date.

If the date is invalid, the validation message pops up but if the person tries to hit the calendar icon, it keeps popping up and the only way to fix the problem is to manually input the correct value in the date field.

Is there a way where I can try to tie in use of the calendar icon so that the onblur event doesn't shoot off so quickly.

I had tried using the onchange event which works if I enter the text manually, but I use the Calendar to populate the field my validations are fired off at all.

Do you have any ideas ?

Thanks again,
Pia
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: dynamic form elements using struts