I created a dynamic Form where the user can add multiple calendar input fields by clicking a command button. My Problem is, that the connection between View and Been is broken. Submitting the form returns the Date created previously in the Bean initially and not the Date submitted by the user. How to fix it?
EDIT: Changing a date and extending the form afterwards without saving before leads to losing the changed date(s). Even with the solution with a wrapper object provided by @wittakarn.
EDIT: The ajax snippet seems to be the problem, when I strip that out it works.
DynamicFormBean:
import java.io.Serializable;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
public class DynamicformBean implements Serializable {
private static final Logger LOGGER = Logger.getLogger(DynamicformBean.class.getName());
private List<Date> values;
@PostConstruct
public void init() {
values = new LinkedList<>();
values.add(new Date());
}
public void submit() {
// save values in database
LOGGER.info(values.toString());
}
public void extend() {
values.add(new Date());
}
public void setValues(List<Date> values) {
this.values = values;
}
public List<Date> getValues() {
return values;
}
}
My View: dynamicform.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<h:form><h2>Dynamicform example</h2>
<ui:repeat value="#{dynamicformBean.values}" var="value">
<p:outputLabel for="mask" value="Mask:" />
<p:calendar id="mask" value="#{value}" pattern="dd.MM.yyyy" mask="true">
<f:convertDateTime pattern="dd.MM.yyyy" timeZone="CET" />
</p:calendar>
<br />
</ui:repeat>
<h:commandButton value="Extend">
<f:ajax listener="#{dynamicformBean.extend}" process="@form" render="@form" />
</h:commandButton>
<h:commandButton action="#{dynamicformBean.submit}" value="Save" />
</h:form>
</h:body>
</f:view>
The log just prints elements with the current date.
I cannot tell in detail why connection between View and Been is broken, but when I wrap object date into Data class as following code. The problem is gone.
xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head><title>Dynamicform example</title></h:head>
<h:body>
<h:form>
<h2>Dynamicform example</h2>
<ui:repeat value="#{dynamicformBean.values}" var="value">
<p:outputLabel for="mask" value="Mask:" />
<p:calendar id="mask"
value="#{value.date}"
pattern="dd.MM.yyyy" mask="true">
<f:convertDateTime pattern="dd.MM.yyyy" timeZone="CET" />
</p:calendar>
<br/>
</ui:repeat>
<h:commandButton value="Extend">
<f:ajax render="@form"
listener="#{dynamicformBean.extend}"/>
</h:commandButton>
<h:commandButton action="#{dynamicformBean.submit}" value="Save"/>
</h:form>
</h:body>
</f:view>
</html>
managedbean
@ManagedBean(name = "dynamicformBean")
@ViewScoped
public class DynamicformBean implements Serializable {
private static final Logger LOGGER = Logger.getLogger(DynamicformBean.class.getName());
private List<Data> values;
@PostConstruct
public void init() {
values = new LinkedList<Data>();
values.add(new Data());
}
public void submit() {
// save values in database
for (Data data : values) {
LOGGER.info(data.getDate().toString());
}
}
public List<Data> getValues() {
return values;
}
public void setValues(List<Data> values) {
this.values = values;
}
public void extend(AjaxBehaviorEvent event) {
LOGGER.info("extend");
values.add(new Data());
}
}
Data object
import java.io.Serializable;
import java.util.Date;
public class Data implements Serializable {
private Date date;
public Data(){
date = new Date();
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
However, you should use JSF Standard tags h:head. PrimeFaces uses it to include the necessary java script and CSS code for the Ajax works and fancy look'n'feel.