How to handle values from dynamically generated elements in web page using struts2



Some time you will see the form containing the button "Add More" . This facility is provided for the user to get the values for unknown number of repeating for some information. for example when you are asking to get the projects details from user, you need to put the option to add the more project for the user since you don't known how many projects user have. In the HTML form, you repeat the particular section to get the multiple values for those elements.

In Html page , you can put the option to add new row of elements or text fields by writing the java script or using JQuery API.

Now, the question is that how to capture the values of dynamically generated text fields on the server. Using the servlet programming you can get the values by using getParameters() method that resultants the array of the parameter having the same name. But this limit you to naming the text fields in the HTML form. To ally this approach, you have to take the same name for the multiple input type fields those will have the similar values. After getting the server side, you need to process these type of fields manually using lots of programing approach. So it is not a feasible solution when there are other approaches available like using Struts2.

Here, I am explaining the approach for the getting over from this problem. We have struts2 MVC framework that has capability to intercept the request parameters submitted from HTML from. It maps the values to the action or bean properties automatically without writing much codes. You need to following some naming convention only. Struts mapping the values of the input type elements of the HTML form to the properties/variable of the action object automatically if you have kept the name of the input type fields and properties same. You can read the struts2 documentation to handle the something in multiple ways.

Now, if there is some multiple fields in the HTML form having repeatedly values, Struts maps those values to the Collection type properties in the Action Object. So to get the values of the field having multiple values but the same name, take the List type variable in Action class. If some properties of the action class pointing other object, struts2 handling it using the naming convention of the input type field.

<INPUT type="text" name="user.addresses.houseNum" />

At the server side, struts2 mappes value of this text filed using OGNL . In the above statement, user is the property of the actiion object and addresses it the property of the user object. Addresses object contains houseNum property in which the value of the above text field will be mapped.
If the User object has the List of Address object , Struts2 to automatically maps the values to this properties using the following naming convention.

<INPUT type="text" name="user.addresses[0].houseNum" />

The value of the text field will be mapped to the property of the first object of the address List contained by the user object.
Here is an application that has the form with id and name text field and option to adding more addresses. User can address any number of address row and all values are processed by server. Here, I am displaying the submitted values in result page but use can change the codding to persist them to database.


index.html
<HTML>
<HEAD>
<TITLE>Add/Remove dynamic rows in HTML table</TITLE>
<SCRIPT language="javascript">
    function addRow(tableID) {

        var table = document.getElementById(tableID);

        var rowCount = table.rows.length;
        var row = table.insertRow(rowCount);
        var counts=rowCount-1;
        var cell1 = row.insertCell(0);
        var houseNum = document.createElement("input");
        houseNum.type = "text";
        houseNum.name="user.addresses["+counts+"].houseNum";
        cell1.appendChild(houseNum);

        var cell2 = row.insertCell(1);
        var city = document.createElement("input");
        city.type = "text";
        city.name="user.addresses["+counts+"].city";
        cell2.appendChild(city);

        var cell3 = row.insertCell(2);
        var country = document.createElement("input");
        country.type = "text";
        country.name="user.addresses["+counts+"].country";
        cell3.appendChild(country);

    }
</SCRIPT>
</HEAD>
<BODY>

<form action="submit" method="post">ID : <INPUT type="text"    name="user.id" /><br />
Name :<INPUT type="text" name="user.name" /><br />
Addresses :
<TABLE id="addressesTable" width="350px" border="1">
    <TR>
        <TD>House No.</TD>
        <TD>City</TD>
        <TD>Country</TD>
    </TR>
    <TR>
        <TD><INPUT type="text" name="user.addresses[0].houseNum" /></TD>
        <TD><INPUT type="text" name="user.addresses[0].city" /></TD>
        <TD><INPUT type="text" name="user.addresses[0].country" /></TD>
    </TR>
</TABLE>
<INPUT type="button" value="Add More" onclick="addRow('addressesTable')" />
<input type="submit" value="SUBMIT"/>
</form>
</BODY>
</HTML>
result.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h1>User information</h1>
Name :<s:property value="user.name" /><br/>
Addresses :
<s:iterator value="user.addresses">
    <br />
    <s:property/>
</s:iterator>
</body>
</html>
web.xml
<web-app> 
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app> 

struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUB
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />
    <package name="/" extends="struts-default">
        <action name="submit" class="UserAction">
            <result name="input">index.jsp</result>
            <result name="success">result.jsp</result>
        </action>
    </package>
</struts>
UserAction.java

import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {
    data.User user;
    public data.User getUser() {
        return user;
    }
    public void setUser(data.User user) {
        this.user = user;
    }
    public String execute(){
        return "success";
    }
}

User.java

package data;

import java.util.Collection;

public class User {
    int id;
    String name;
    Collection <Address> addresses;
    public Collection<Address> getAddresses() {
        return addresses;
    }
    public void setAddresses(Collection<Address> addresses) {
        this.addresses = addresses;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", addresses=" + addresses
                + "]";
    }
    
}

Address.java
package data;

public class Address {
    private int houseNum;
    private String city;
    private String country;

    public int getHouseNum() {
        return houseNum;
    }

    public void setHouseNum(int houseNum) {
        this.houseNum = houseNum;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "Address [houseNum=" + houseNum + ", city=" + city
                + ", country=" + country + "]";
    }

}



Download source

24 comments:

Anonymous said...

Very helpful example. I have sorted out my problem now.

thanks

Asit Jaiswal said...

Good post really helped me to solve my problem
Thanks.
Asit Jaiswal

swathi said...

Hi,
Here you are reading this dynamic values in another html page right.but i want to read it in struts2 action class...
is it possible

Hemraj said...

Hi swathi,I am reading values in UserAction class and UserAction class is storing values in User object and Address object. Second page is displaying values from user object only. To see the values in action class, write System.out.println(user); in execute method of UserAction class.

Joel Jil Garay said...

Muchas Gracias! :)

Anonymous said...

How can I display the same values on the same page, on the same text fields and not in a label form?

Thanks

RameshGanesan said...

Hi,

I'm dynamically creating a row using Javascript function,The row which i have created has a datepicker control along with the textbox,let me know how do i populate value in the textbox with when the user selects the datepicker for the newly added row.


Thanks,
Ramesh.

surendra said...

hi i am getting some problem while i am trying to save dynamic datas in database ,please help me for inserting only dynamic datas into database

Hemraj said...

Since All data captured from the form is mapped to the user object in UserAction class, you can write the simple Hiberntate code in execute method to persist the user object in database.

you can see this link for getting help in hibernate : http://www.programmingforfuture.com/2010/06/hibernate-introduction.html

surendra said...

Hello Hemraj,
Thanks for helping,But I have to save dynamic data in different rows in databse with its respected auto incremented ids and i am unable to read dynamic datas seperately or according to number of textfields
I am trying this as such type :
ArrayList arr=new ArrayList();
arr = (ArrayList)(getUser().getAddresses());
System.out.println("String is is-->"+user); //this returns all dynamic values
arr.add(getUser().getAddresses());
System.out.println("arr is-->"+arr); //this returns all dynamic values in arraylist
System.out.println("values are-->"+getUser().getName()); //this returs name
System.out.println("values are-->"+(getUser().getAddresses()).size()); //this returns all dynamic values
for(int i=0;i<(getUser().getAddresses()).size();i++)
{
system.out.println("values are-->"+(String)((ArrayList)(arr.get(i)).get(0))); //it seems runtime error
}
note:I have also changed address.java to ,Plaease help me to Type cast this getUser().getAddresses() or user to String Array Form
package data;
public class Address {
private String city;
public String getCity() {
return city; }
public void setCity(String city) {
this.city = city; }
@Override
public String toString() {
return city; }
}
(because i needed only single dynamic textbox i.e city and also changed in jsp accordingly)
please help me to read dynamic datas seperately according to loop

Hemraj said...

Just write down following codes in execute method to insert the data of form in tables. Actually data goes to 2 tables one is Usertable and another is addresstable. you can create the table by seeing the insert query parameters and user this code to insert the data.

public String execute(){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con=DriverManager.getConnection("jdbc:odbc:mydatasource");

//Insert the data of user object,id value can be set to increatment or you can provide unique value yourself as it is a PK.
PreparedStatement ps = con.prepareStatement("insert into userTable(id,name) values(?,?)");
ps.clearParameters();
ps.setInt(1, user.getId());
ps.setString(2, user.getName());
ps.executeUpdate();
ps.close();

//now insert the multiple addresses for this particular user. You have to user user Id as foregain key in address table to identify the addresses for particular user.
PreparedStatement ps2 = con.prepareStatement("insert into userAddress(houseNum,city,country,userId) values(?,?,?,?)");
Collection<Address> addresses = user.getAddresses();
for (Address address : addresses) {
ps2.clearParameters();
ps2.setInt(1, address.getHouseNum());
ps2.setString(2, address.getCity());
ps2.setString(2, address.getCountry());
ps2.setInt(3, user.getId());
ps2.executeUpdate();
}
ps2.close();

} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return "success";
}

surendra said...

This makes easy to read data separately according to no. of rows.
Thanks Hemraj
Surendra Kumar sharma

surendra said...

Hello Hemraj ,Please help me
I am facing some problem of null pointer exception while trying to read csv file

This code works properly in servlet but not in struts2
kindly help me for reading datas from csv file in struts2

My java code is:-

package question;
import java.util.ArrayList;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ActionContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.io.FileUtils;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.File;
import java.util.*;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class Test extends ActionSupport {
//private HttpServletRequest servletRequest;
private HttpServletResponse response;
private HttpServletRequest request;
private static String REAL_PATH = null;
public void setServletRequest( HttpServletRequest request ) {
this.request = request;
REAL_PATH = this.request.getRealPath( "/" );}
public HttpServletRequest getServletRequest() {
return request; }
public void setServletResponse( HttpServletResponse response ) {
this.response = response;}
private static final long serialVersionUID = 1L;
private File csv;
public String addQues()
{
String result = ERROR,sql="",noneOfAbVal="",otherVal="";
if(getCsv() != null)
{
DataInputStream dis = null;
String filename="",msg="",test="",record=null,photoid="",val1="",val2="",str="";
int index=0,j=0,index1=0;
try
{
List items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(getServletRequest());//This line can't recognize
for (FileItem item : items)
{
if (item.getFieldName().equals("csv"))
{
InputStream input=item.getInputStream();
BufferedInputStream bis = new BufferedInputStream(input);
dis = new DataInputStream(bis);
String[] contents=new String[2000];
while( (record=dis.readLine()) != null )
{
contents[j]=record;
//System.out.println("right here--4-->"+contents[j]);
j++;
}
for(int count=0;count<j;count++)
{ index=contents[count].indexOf(",");
val1=contents[count].substring(0,index);
val2=contents[count].substring(index+1);
System.out.println("Val1="+val1);
System.out.println("Val2="+val2);
}
}
}
}
catch(Exception e) { e.printStackTrace();}
}
result=SUCCESS;
return result;
}
public File getCsv() {
return csv; }
public void setCsv(File csv) {
this.csv = csv;
}
}

hakima said...

tanks ,very helpful

Sergio said...

Thanks by the idea !!!
But if you have a esample using struts1 it would be nice !

Regards from Brasil.

sravani said...

Hai Hemraj

Can we retrieve rowcount value from index.jsp to Action class?

Hemraj said...

You have to take a hidden text field like - <input type="hidden" name="rowCount" id="rowCount"/>

And then set the value of rowCount variable(in javascript) to this field.

document.getElementById('rowCount').value=rowCount;

this field will be submitted alongwith form and you can get this value in action class property "rowCount".
2nd approach:- if you want to get the number of rows, then just get the size of collection addresses in user object.

Ajitha Chandran said...

Thank you...
:)

nawalkishore388@gmail.com said...

How to write such program using servlet and jsp, I am trying it since 10 days but i am getting trouble to do it.

I am trying to devlope onling billing system in which user can add multiple rows as requirment, but i am stuck here.

Hemraj said...

You can submit multiple values with same name of multiple input text boxes. In Servlet you will extract values suing String values[]=request.getParameterValues("param-name");

It will return array of string having multiple values of a input box name.

Binh Thanh Nguyen said...

Thanks, nice tips

Debasmita Pattnayak said...

Hi Hemraj,

thanks for the wonderful post...it was indeed helpful...
I am trying to do the exact thing, but I am wondering how it can be achieved using Struts 1.2.9...

I am stuck badly. If you could help, then it would really be great.

Awaiting your kind response.

Abi said...

Really Thanks a lot.my big prob is solved

Anonymous said...

the collection comes up empty in the action class..any idea on why that could be?

Popular Posts