Skip to main content

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

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.
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.
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.
Unknown 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 from this blog

Using HyperSQL (HSQLDB)

HSQLDB is a portable RDBMS implemented in pure java. It can be embedded with your application as well as can be used separately. It is very a small database that supports almost all features of the standard database system. It comes with small jar file that can be found in lib folder. The HSQLDB jar package is located in the /lib directory of the ZIP package and contains several components and programs. Core components of jar file are : HyperSQL RDBMS Engine (HSQLDB), HyperSQL JDBC Driver, Database Manager, and Sql Tool. Installing and Using Download: download latest release of HyperSQL database from http://hsqldb.org website and extract it. You will see following contents. Here "bin" directory contains some batch files those can be used to run a swing based GUI tool. You can use runManagerSwing.bat to connect to database, but database must be on before running it. Directory lib contains File hsqldb.jar . It is the database to be used by you. Running database First

In Process Mode of HSQLDB in web application.

If you want to use the database into your web application, you can use the HSQLDB in In_Process mode. In this mode, you can embed the HSQLDB into your web application and it runs as a part of your web application programm in the same JVM. In this mode, the database does not open any port to connect to the application on the hosing machine and you don't need to configure anything to access it. Database is not expposed to other application and can not be accessed from any dabase tools like dbVisualizer etc. In this mode ,database will be unknown from any other person except you. But in the 1.8.0 version, you can use Server intance for external as well as in process access.  To close the databse, you can issue SHUTDOWN command as an SQL query.   In the in-process mode, database starts from JDBC with the associated databse file provided through  connection URL. for example   DriverManager.getConnection("jdbc:hsqldb:mydatabase","SA","");   Here myd