I am facing an issue with dynamic list binding in Spring. I am trying to create an "Add Contact" page which basically looks like this:
When the "Add Phone" button is clicked I want another "Phone Type" and "Phone Number" button to appear below so that the user can enter multiple phone numbers. This is where I am facing issues.
Below is my code:
Domain Class - Contact:
In my form, The First Name, Last Name, Email and Birthday are instance variable of the domain class "Contact" and Phone Type and Phone Number of the part of List Phones.
@Entity
@Table(name = "CONTACTS_JPA2")
public class Contact {
@Id
@Column(name = "CONTACT_ID")
@GeneratedValue
private int Id;
@Column(name = "FIRST_NAME")
private String firstname;
@Column(name = "LAST_NAME")
private String lastname;
@SuppressWarnings("unchecked")
@OneToMany(mappedBy = "contact", cascade = CascadeType.ALL)
private List<Phone> phones = LazyList.decorate(new ArrayList<Phone>(),FactoryUtils.instantiateFactory(Phone.class));
@Column(name = "EMAIL_ID")
private String emailid;
@Column(name = "BIRTHDAY")
private Date birthday;
/*Getters and Setters*/
}
Class Phone:
@Entity
@Table(name = "PHONE")
public class Phone {
@Id
@Column(name = "ID")
private int Id;
@Column(name = "PHONE_NBR")
private String phonenumber;
@Column(name = "PHONE_TYPE")
private String phonetype;
@ManyToOne()
@JoinColumn(name = "CONTACT_ID")
private Contact contact;
/*Getters and Setter*/
}
HTML Form(JSP):
<form:form id = "addcontactform" name="addcontact" method="POST" commandName="contact">
<table>
<tr>
<td>First Name:</td>
<td><form:input name = "firstname" id = "firstname" path="firstname" value=''/></td>
<td>Last Name:</td>
<td><form:input name = "lastname" id = "lastname" path="lastname" value=''/></td>
</tr>
<tr>
<td>Email:</td>
<td><form:input name = "emailid" id = "emailid" path="emailid"/></td>
</tr>
<tr>
<td>Phone Type:</td>
<td>
<spring:bind path = "contact.phones[0].phonetype">
<form:select id ="phonetype" name="phonetype" path="${status.expression}">
<option value="-- Select Phone Type --">-- Select Phone Type --</option>
<option value="Home">Home</option>
<option value="Cell">Cell</option>
<option value="Work">Work</option>
</form:select>
</spring:bind>
</td>
<td>Phone Number:</td>
<td>
<spring:bind path = "contact.phones[0].phonenumber">
<form:input name = "phonenumber" id = "phonenumber" path="${status.expression}" value=''/>
</spring:bind>
</td>
<td><form:button type = "button" id = "addphone">Add Phone</form:button>
</tr>
<tr>
<td>Birthday:</td>
<td><form:input id = "birthday" path="birthday" value=''/></td>
</tr>
</table>
</div>
<input type="submit" id = "mysubmit" name="mysubmit" value="Add Contact" />
</div>
</form:form>
Javascript on the above form:
What I am trying to do here is, when the "Add Phone" button is clicked, I send out an AJAX request to the server with the count of the row to be inserted.
<script type="text/javascript" src="${pageContext.request.contextPath}/resources/scripts/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('#addphone').click(function(){
phonecount++;
alert('Addinh phone '+phonecount);
$.get("displayaddphone", {count : phonecount},callback);
function callback(data){
alert('in Callback');
$("#addphone").before(data);
};
return false;
});
</script>
Controller method called on AJAX request: It adds the row count to the model and returns a jsp - addnewphone.jsp
@RequestMapping(value = "/displayaddphone")
public String appendaddphone(@RequestParam(value="count") int addphonecount,ModelMap model){
model.addAttribute("addphonecount", addphonecount);
return "addnewphone";
}
addnewphone JSP: This contains the HTML fragment for the new row.
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<tr>
<td>Phone Type:</td>
<td>
<form:select id ="phonetype" name="phonetype" path="contact.phones[${addphnbr}].phonetype">
<option value="-- Select Phone Type --">-- Select Phone Type --</option>
<option value="Home">Home</option>
<option value="Cell">Cell</option>
<option value="Work">Work</option>
</form:select>
</td>
<td>Phone Number:</td>
<td>
<form:input name = "phonenumber" id = "phonenumber" path="contact.phones[${addphnbr}].phonenumber" value=''/>
</td>
</tr>
I am trying to pass this view(contained in the variable 'data') into my AJAX callback function in the above javascript and add it to my original "Add Contact" form using - $("#addphone").before(data);
I am getting the following error when I click the "Add Phone button":
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/ContactList-JPA2] threw exception [java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'contact' available as request attribute] with root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'contact' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(Abs tractDataBoundFormElementTag.java:178)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:198)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:164)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:127)
at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:421)
at org.springframework.web.servlet.tags.form.SelectTag.writeTagContent(SelectTag.java:199)
at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:102)
at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:79)
at org.apache.jsp.WEB_002dINF.views.addnewphone_jsp._jspx_meth_form_005fselect_005f0(addnewphone_jsp.java:117)
at org.apache.jsp.WEB_002dINF.views.addnewphone_jsp._jspService(addnewphone_jsp.java:76)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:690)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:477)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:402)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:329)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:238)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:262)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1157)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:927)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:827)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:311)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:101)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:182)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at com.springsource.insight.collection.tcserver.request.HttpRequestOperationCollectionValve.invoke(HttpRequestOperationCollectionValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Basically, I am trying to contruct the HTML that I want to add in my main page in a separate jsp and trying to add that to my form dynamically. Is this a correct approach at all for my scenario. Please advice.
You are accepting something like contact.phones[${addphnbr}].phonetype in your jsp. And your controller has not sent this information along with jsp. That is why this error.
Your controller should provide "contact" attribute to your jsp. Now you are sending "addphonecount" to jsp and you dont seem to use it on jsp. You might need to send "contact" instead.
@RequestMapping(value = "/displayaddphone")
public String appendaddphone(@RequestParam(value="count") int addphonecount,ModelMap model){
// define "contact" object, suppose for example
Contact contact = populateContact();
model.addAttribute("contact", contact);
return "addnewphone";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With