The datatable displays entries that I intend to be able to edit. In order to do so, I use a commandlink to open a dialog box. setPropertyActionListener sets the CostingType object that should be able to be modified from within the dialog box. However, the dialog box isn't able to get the object's variables or save them. Instead, it shows an empty object and clicking on the edit button(after keying in fields) shows the requiredMessage warnings instead. checkEdit() (which exists solely for debug purposes) isn't being called either.
HTML:
<h:form id="costingTypeForm" >
<p:tabView id="tabView">
<p:tab id="tab1" title="Costing Type">
<h:form id="costingTypeForm" >
<p:tabView id="tabView">
<p:tab id="tab1" title="Costing Type">
<p:dataTable
id="costingTypeTable"
value="#{costingTypeBean.costingTypeList}"
var="costingType"
rows="#{psmsProp['psms.dataTable.rows']}"
paginator="true"
paginatorTemplate="{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown} {CurrentPageReport}"
rowsPerPageTemplate="#{psmsProp['psms.dataTable.rowsPerPage']}"
currentPageReportTemplate="Displaying {startRecord}-{endRecord} out of {totalRecords}"
style="width:80%; text-align:center;"
sortBy="#{costingType.name}"
sortMode="single" >
<f:facet name="header">
Costing Type
<p:commandButton
value="Add"
oncomplete="PF('addCostingTypeDialog').show()"
update="costingTypeForm:tabView:addCostingTypeForm"
icon="ui-icon-plus"
style="float:right;" />
<div style="clear:both" />
</f:facet>
<p:column sortBy="#{costingType.name}"
filterBy="#{costingType.name}"
filterMatchMode="contains"
filterFunction="#{filterUtil.containsFilter}"
filterStyle="width:80%;"
headerText="Name">
<p:outputLabel id = "name" value="#{costingType.name}" />
</p:column>
<p:column headerText="Description">
<p:outputLabel id = "description" value="#{costingType.nameDesc}" />
</p:column>
<p:column headerText="Budgeted">
<p:outputLabel value="Yes" rendered="#{costingType.budget}" />
<p:outputLabel value="No" rendered="#{not costingType.budget}" />
</p:column>
<p:column headerText="Deleted">
<p:outputLabel value="Yes" rendered="#{costingType.del}" />
<p:outputLabel value="No" rendered="#{not costingType.del}" />
</p:column>
<p:column>
<p:commandLink
oncomplete="PF('editCostingTypeDialog').show()"
update=":costingTypeForm:tabView:editCostingTypeForm"
value="Edit" action="#{costingTypeBean.checkEdit}">
<f:setPropertyActionListener target="#{costingTypeBean.editCostingType}" value="#{costingType}"/>
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog
header="Edit Costing Type"
widgetVar="editCostingTypeDialog"
modal="true"
showEffect="slide"
hideEffect="fade"
resizable="false"
closable="false">
<p:outputPanel id="editCostingTypeForm">
<p:panelGrid columns="2" cellpadding="5" rendered="#{not empty costingTypeBean.editCostingType}">
<h:panelGroup>
<p:outputLabel value="Name:" />
<p:outputLabel value="*" style="color:red;" />
</h:panelGroup>
<p:inputText value="#{costingTypeBean.editCostingType.name}" required="true" requiredMessage="Name is required" />
<h:panelGroup>
<p:outputLabel value="Description:" />
<p:outputLabel value="*" style="color:red;" />
</h:panelGroup>
<p:inputText value="#{costingTypeBean.editCostingType.nameDesc}" required="true" requiredMessage="Description is required" />
<p:outputLabel value="Budgeted:" />
<p:selectOneMenu value="#{costingTypeBean.editCostingType.budget}">
<f:selectItem itemValue="true" itemLabel="Yes" />
<f:selectItem itemValue="false" itemLabel="No" />
</p:selectOneMenu>
<h:outputLabel value="Deleted:" />
<p:selectOneMenu value="#{costingTypeBean.editCostingType.del}">
<f:selectItem itemValue="true" itemLabel="Yes" />
<f:selectItem itemValue="false" itemLabel="No" />
</p:selectOneMenu>
</p:panelGrid>
<p:commandButton
value="Cancel"
actionListener="#{costingTypeBean.cancelChange}"
oncomplete="PF('editCostingTypeDialog').hide();"
icon="ui-icon-close"
style="float:right;margin-top:10px;margin-bottom:10px;" />
<p:commandButton
value="Edit"
actionListener="#{costingTypeBean.updateCostingType}"
oncomplete="if(args.update) PF('editCostingTypeDialog').hide();"
update=":costingTypeForm:messages #(.ui-datatable)"
icon="ui-icon-disk"
style="float:right;margin-top:10px;margin-right:10px;margin-bottom:10px;" />
</p:outputPanel>
</p:dialog>
<p:dialog
header="Add New CostingType"
widgetVar="addCostingTypeDialog"
modal="true"
showEffect="slide"
hideEffect="fade"
resizable="false"
closable="false">
<p:outputPanel id="addCostingTypeForm">
<p:panelGrid columns="2" cellpadding="5">
<h:panelGroup>
<p:outputLabel value="Name" />
<p:outputLabel value="*" style="color:red;" />
</h:panelGroup>
<p:inputText value="#{costingTypeBean.name}" required="true" requiredMessage="Enter name" />
<h:panelGroup>
<p:outputLabel value="Description:" />
<p:outputLabel value="*" style="color:red;" />
</h:panelGroup>
<p:inputText value="#{costingTypeBean.nameDesc}" required="true" requiredMessage="Enter Engine Type" />
<h:panelGroup>
<h:outputLabel value="Budgeted:" />
<p:outputLabel value="*" style="color:red;" />
</h:panelGroup>
<p:selectOneRadio value="#{costingTypeBean.budgeted}">
<f:selectItem itemValue="true" itemLabel="Yes" />
<f:selectItem itemValue="false" itemLabel="No" />
</p:selectOneRadio>
<h:panelGroup>
<h:outputLabel value="Deleted:" />
<p:outputLabel value="*" style="color:red;" />
</h:panelGroup>
<p:selectOneRadio value="#{costingTypeBean.deleted}">
<f:selectItem itemValue="true" itemLabel="Yes" />
<f:selectItem itemValue="false" itemLabel="No" />
</p:selectOneRadio>
</p:panelGrid>
<p:commandButton
value="Cancel"
actionListener="#{costingTypeBean.cancelChange}"
oncomplete="PF('addCostingTypeDialog').hide();"
icon="ui-icon-close"
style="float:right;margin-top:10px;margin-bottom:10px;" />
<p:commandButton
value="Save"
actionListener="#{costingTypeBean.addCostingType}"
oncomplete="if(args.add) PF('addCostingTypeDialog').hide(); else PF('addCostingTypeDialog').show();"
update="#form #(.ui-datatable)"
icon="ui-icon-disk"
style="float:right;margin-top:10px;margin-right:10px;margin-bottom:10px;" />
</p:outputPanel>
</p:dialog>
</p:tab>
</p:tabView>
</h:form>
Backing bean:
#Component
#Scope("view")
public class CostingTypeBean{
private static final Logger LOGGER = LoggerFactory.getLogger(CostingTypeBean.class);
private long costingTypeId;
private boolean budgeted, deleted;
private String name, nameDesc;
private CostingType costingType;
private CostingType editCostingType;
private List<CostingType> costingTypeList;
#Autowired
private CostingTypeService costingTypeService;
/*
getters and setters
*/
// dialog edit
public void updateCostingType(ActionEvent event) {
RequestContext context = RequestContext.getCurrentInstance();
if(editCostingType!=null) {
costingTypeService.saveOrUpdate(editCostingType);
context.addCallbackParam("update", true);
}
else
context.addCallbackParam("update", false);
}
//debug method
public void checkEdit() {
LOGGER.debug("Edit listener");
ViewUtil.showInfo("Edit dialog triggered");
System.out.println("Edit listener");
}
What should I do to get editCostingTypeDialog to reflect the fields of of the CostingType object and be able to read the values keyed in the input text areas?
Your code works just fine. All I had to do was to modify some of the update= attributes (as I was getting exceptions about destination components not being found). After populating with some random data and using your above code I get the following;
I tested with both PrimeFaces 6.1 and 6.2 on Mojarra 2.3.3.99. The backing bean callback for the edit button in the dialog is also being called properly.
So the next thing to check - which JSF implementation are you using? Is it Mojarra or MyFaces ? which version ? Maybe you are hitting upon some bug in your specific implementation. There is absolutely nothing wrong with your code.
While I'm at it, I might as well post the complete code (including my modifications);
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Costing type Test</title>
</h:head>
<h:body>
<h:form id="costingTypeForm" >
<p:tabView id="tabView">
<p:tab id="tab1" title="Costing Type">
<p:dataTable
id="costingTypeTable"
value="#{costingTypeBean.costingTypeList}"
var="costingType"
paginator="true"
style="width:80%; text-align:center;"
sortMode="single" >
<f:facet name="header">
Costing Type
<p:commandButton value="Add" oncomplete="PF('addCostingTypeDialog').show()" update="#form" icon="ui-icon-plus" style="float:right;" />
<div style="clear:both" />
</f:facet>
<p:column sortBy="#{costingType.name}"
filterBy="#{costingType.name}"
filterMatchMode="contains"
filterFunction="#{filterUtil.containsFilter}"
filterStyle="width:80%;"
headerText="Name">
<p:outputLabel id = "name" value="#{costingType.name}" />
</p:column>
<p:column headerText="Description">
<p:outputLabel id = "description" value="#{costingType.nameDesc}" />
</p:column>
<p:column headerText="Budgeted">
<p:outputLabel value="Yes" rendered="#{costingType.budget}" />
<p:outputLabel value="No" rendered="#{not costingType.budget}" />
</p:column>
<p:column headerText="Deleted">
<p:outputLabel value="Yes" rendered="#{costingType.del}" />
<p:outputLabel value="No" rendered="#{not costingType.del}" />
</p:column>
<p:column>
<p:commandLink
oncomplete="PF('editCostingTypeDialog').show()"
update=":costingTypeForm:tabView:editCostingTypeForm"
value="Edit" action="#{costingTypeBean.checkEdit}">
<f:setPropertyActionListener target="#{costingTypeBean.editCostingType}" value="#{costingType}"/>
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog
header="Edit Costing Type"
widgetVar="editCostingTypeDialog"
modal="true"
showEffect="slide"
hideEffect="fade"
resizable="false"
closable="false">
<p:outputPanel id="editCostingTypeForm">
<p:panelGrid columns="2" rendered="#{not empty costingTypeBean.editCostingType}">
<h:panelGroup>
<p:outputLabel value="Name:" />
<p:outputLabel value="*" style="color:red;" />
</h:panelGroup>
<p:inputText value="#{costingTypeBean.editCostingType.name}" required="true" requiredMessage="Name is required" />
<h:panelGroup>
<p:outputLabel value="Description:" />
<p:outputLabel value="*" style="color:red;" />
</h:panelGroup>
<p:inputText value="#{costingTypeBean.editCostingType.nameDesc}" required="true" requiredMessage="Description is required" />
<p:outputLabel value="Budgeted:" />
<p:selectOneMenu value="#{costingTypeBean.editCostingType.budget}">
<f:selectItem itemValue="true" itemLabel="Yes" />
<f:selectItem itemValue="false" itemLabel="No" />
</p:selectOneMenu>
<h:outputLabel value="Deleted:" />
<p:selectOneMenu value="#{costingTypeBean.editCostingType.del}">
<f:selectItem itemValue="true" itemLabel="Yes" />
<f:selectItem itemValue="false" itemLabel="No" />
</p:selectOneMenu>
</p:panelGrid>
<p:commandButton
value="Cancel"
actionListener="#{costingTypeBean.cancelChange}"
oncomplete="PF('editCostingTypeDialog').hide();"
icon="ui-icon-close"
style="float:right;margin-top:10px;margin-bottom:10px;" />
<p:commandButton
value="Edit"
actionListener="#{costingTypeBean.updateCostingType}"
oncomplete="if(args.update) PF('editCostingTypeDialog').hide();"
update="#form"
icon="ui-icon-disk"
style="float:right;margin-top:10px;margin-right:10px;margin-bottom:10px;" />
</p:outputPanel>
</p:dialog>
</p:tab>
</p:tabView>
</h:form>
</h:body>
</html>
And here is the backing bean (example uses Lombok and Apache Commons);
#Data
#Named
#ViewScoped
public class CostingTypeBean implements Serializable {
private CostingType costingType;
private CostingType editCostingType;
private List<CostingType> costingTypeList;
#PostConstruct
private void init() {
costingTypeList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
final String name = RandomStringUtils.randomAlphanumeric(10);
final String nameDesc = RandomStringUtils.randomAlphanumeric(10);
final boolean budget = RandomUtils.nextBoolean();
final boolean del = RandomUtils.nextBoolean();
costingTypeList.add(new CostingType(name, nameDesc, budget, del));
}
}
public void updateCostingType(ActionEvent event) {
System.out.println("update!");
}
public void checkEdit() {
System.out.println("Edit listener");
}
public void cancelChange() {
System.out.println("Cancel");
}
#Data
#AllArgsConstructor
public class CostingType {
private String name;
private String nameDesc;
private boolean budget;
private boolean del;
}
}
Hopefully this can be of some help.
It's a bug in PrimeFaces (I think).
I searched with many tests in a minimal test application. It's not possible to use following constellation:
<p:dataTable value="#{bean.list}" var="myVar".....
<p:ajax event="rowSelect" partialSubmit="true" process="#this" listener="#{bean.doWork(myVar)}"/>
bean.doWork() will always be called with a null pointer.
Glassfish 4.1.1
PrimeFaces 6.2
I think your problem is the same.
Related
I have a bandbox with a Listbox inside.
My Listbox has "onSelect" listener, and inside this i do a myListbox.clearSelection()
after read the value of the selected item and write it on a TextBox.
The problem is, that when I open the bandpopup another time, the selected item in the List remain selected and Marked in blue color, and i can't select the same element twice because it's remain selected.
For example:
Open the Bandpopup.
Clik in a element, the value is written on the Textbox, and then learSelection()" is called.
The user clear the Textbox.
Reopen the Bandpopup.
Click on the same item in the ListBox.
Nothing occurs, because this element remains selected.
The Zul code:
<?page title="Enviar a" contentType="text/html;charset=UTF-8"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" arg0="./envioWindow" ?>
<zk>
<window title="Enviar a" border="normal" width="60%" id="envioWindow"
apply="..............">
<bandbox id="sectorReparticionBusquedaSADE" >
<bandpopup apply="XXXXXX.FindSectorReparticionesBusquedaSADEBandboxComposer"
id="sectorReparticionesComboBusquedaSADE" width="650px">
<groupbox mold="3d">
<vbox>
<hbox>
<textbox id="textoSectorReparticionBusquedaSADE" />
</hbox>
<paging id="pagingSectorReparticionesDocsSADE" pageSize="10" />
<listbox mold="paging"
width="600px" id="sectoresReparticionesBusquedaSADEListbox"
model="#{listaSectorReparticionSADESeleccionada}"
selectedItem="#{sectorReparticionSeleccionada}"
paginal="${pagingSectorReparticionesDocsSADE}">
<listhead>
<listheader label="Código" width="30%" />
<listheader label="Nombre" height="70%" />
</listhead>
<listitem self="#{each=reparticion}">
<listcell label="#{reparticion.codigo}" />
<listcell label="#{reparticion.nombre}" />
</listitem>
</listbox>
</vbox>
</groupbox>
</bandpopup>
</bandbox>
<bandbox id="sectorBusquedaSADE" tooltiptext="Ingrese el nombre del sector correspondiente a la repartición seleccionada a la que desea agregar para enviarle un pase múltiple." >
<bandpopup apply="ar.gob.gcaba.ee.satra.pl.consulta.FindSectorBusquedaSADEBandboxComposer"
id="sectorComboBusquedaSADE" width="650px">
<groupbox mold="3d">
<vbox>
<hbox>
<textbox id="textoSectorBusquedaSADE" />
</hbox>
<paging id="pagingSectorDocsSADE" pageSize="10" />
<listbox mold="paging"
width="600px" id="sectoresBusquedaSADEListbox"
model="#{listaSectorSADESeleccionado}"
selectedItem="#{sectorSeleccionado}"
paginal="${pagingSectorDocsSADE}">
<listhead>
<listheader label="Código" width="30%" />
<listheader label="Nombre" height="70%" />
</listhead>
<listitem self="#{each=sector}">
<listcell label="#{sector.codigo}" />
<listcell label="#{sector.nombre}" />
</listitem>
</listbox>
</vbox>
</groupbox>
</bandpopup>
</bandbox>
</window>
</zk>
The listbox "sectoresReparticionesBusquedaSADEListbox" has the problem, the "sectoresBusquedaSADEListbox" don't have this problem, and for me both are equal.
I finally solved this resetting the binder every time thath i open the BandPopup:
private void resetComponent() {
this.binder = new AnnotateDataBinder(sectoresReparticionesBusquedaSADEListbox);
this.binder.bindBean("sectorReparticionSeleccionada", this.sectorReparticionSeleccionada);
this.binder.loadAll();
this.listaSectorReparticionSeleccionada = new ArrayList<ReparticionBean>();
this.binder.bindBean("listaSectorReparticionSADESeleccionada", this.listaSectorReparticionSeleccionada);
}
well, simply...the trouble is while i try to run my jsf proyect using primefaces, it does not..and splash on the browser an error screen what says
"Estado HTTP 500 - Error Parsing /Lista.xhtml: Error Traced[line: 37] El tipo de elemento "p:dataTable" debe ir seguido de una de estas especificaciones de atributo: ">" o "/>"."
"HTTP Status 500 - /Lista.xhtml Parsing Error: Error Traced [line 37] The type of element "p: dataTable" must be followed by one of these attribute specifications, ">" or "/>"."
well i tried anything even clean and validating and looking minutely each codeline, so..please help ill be glad of your help...
here is my code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="Template.xhtml">
<ui:define name="content">
<h:head>
<title>Welcome</title>
</h:head>
<h:body>
<h:form>
<p:panelGrid style="margin: 0 auto" columns="2">
<p:outputLabel value="Nombres" />
<p:inputText p:placeholder="Ej; Edward" value="#{personaBean.persona.nombre}"></p:inputText>
<p:outputLabel value="Apellidos" />
<p:inputText p:placeholder="Ej; Snowden"
value="#{personaBean.persona.apellido}" />
<p:outputLabel value="Sexo" style="center" />
<p:selectOneMenu value="#{personaBean.persona.sexo}">
<f:selectItem itemValue="Masculino." itemLabel="Masculino." />
<f:selectItem itemValue="Femenino." itemLabel="Femenino." />
</p:selectOneMenu>
<p:commandButton value="Enviar" actionListener="#{personaBean.agregamePersona}" update="dt" ></p:commandButton>
</p:panelGrid>
<!-- <p:growl id="msj" showDetail="true"/> -->
<p:dataTable id="dt"
value="#{personaBean.lstPersonas}"
border="1"var="p" rows="4"
paginator="true"
paginatorTemplate="{CurrentPageReport}
{FirstPageLink}
{PreviousPageLink}
{PageLinks}
{NextPageLink}
{LastPageLink}
{Exporters}"
tableStyle="widh:auto"
rowsPerPageTemplate="1,2,3,5" >
<p:column filterBy="#{p.nombre}" filterMatchMode="contains"headerText="Nombre" style="width:100px" >
<h:outputText value="#{p.nombre}" />
</p:column>
<p:column headerText="Apellido" filterBy="#{p.apellido}" filterMatchMode="contains"style="width:100px">
<h:outputText value="#{p.apellido}" />
</p:column>
<p:column headerText="Sexo" filterBy="#{p.sexo}" filterMatchMode="contains"style="width:100px" sortBy="#{p.sexo}">
<h:outputText value="#{p.sexo}" />
</p:column>
<p:column style="width:40px">
<h:panelGrid columns="3" styleClass="Actions" cellpadding="2">
<p:commandButton id="eraseButton" value="Eliminar"actionListener="#{personaBean.eliminamePersona(p)}" update="dt" />
<p:commandButton id="selectButton" update=":form:display" oncomplete="interactiveDialog.show()" icon="ui-icon-search" title="View">
<f:setPropertyActionListener value="#{p}" target="#{personaBean.persona}" />
</p:commandButton>
</h:panelGrid>
</p:column>
</p:dataTable>
<p:dialog header="Detalle del cliente" widgetVar="interactiveDialog" resizable="false" id="dialogointeractivo"
showEffect="fade" hideEffect="explode" modal="true">
<h:panelGrid id="display" columns="2" cellpadding="4" style="margin:0 auto;">
<f:facet name="header">
<h:outputText value="Datos de la fila seleccionada"/>
</f:facet>
<h:outputText value="Nombre"/>
<h:outputText value="#{personaBean.persona.nombre}" style="font-weight:bold"/>
<h:outputText value="Apellido"/>
<h:outputText value="#{personaBean.persona.apellido}" style="font-weight:bold"/>
<h:outputText value="Sexo"/>
<h:outputText value="#{personaBean.persona.sexo}" style="font-weight:bold"/>
</h:panelGrid>
</p:dialog>
</h:form>
</h:body>
</ui:define>
</ui:composition>
</html>
I am using the following update method in the bean class:
public String updateAction() {
for ( Login lis: list){
lis.setEditable(false);
setEditable(false);
}
return null;
}
the xhtml file looks like:
<h:dataTable value="#{loginBean.list}" var="list" border="1" >
<h:column>
<f:facet name="header">Name</f:facet>
<h:inputText value="#{list.UName}" size="10" rendered="#{loginBean.editable}" />
<h:outputText value="#{list.UName}" rendered="#{not loginBean.editable}" />
</h:column>
<h:column>
<f:facet name="header">Email</f:facet>
<h:inputText value="#{list.emailAdd}" size="10" rendered="#{loginBean.editable}" />
<h:outputText value="#{list.emailAdd}" rendered="#{not loginBean.editable}" />
</h:column>
<h:column>
<f:facet name="header">Password</f:facet>
<h:inputText value="#{list.pword}" size="10" rendered="#{loginBean.editable}" />
<h:outputText value="#{list.pword}" rendered="#{not loginBean.editable}" />
</h:column>
<h:column>
<f:facet name="header">Edit</f:facet>
<!-- <h:commandLink value="Edit" action="#{loginBean.editAction(list)}"/> -->
<h:commandLink value="Edit" action="#{loginBean.editAction(list)}" />
</h:column>
<h:column>
<f:facet name="header">Delete</f:facet>
<h:commandLink value="Delete" action="#{loginBean.deleteAction(list)}" />
</h:column>
</h:dataTable>
<h:column>
<f:facet name="header">Save</f:facet>
<h:commandButton value="Save" action="#{loginBean.updateAction}" />
</h:column>
</h:form>
When i make changes in a row, and press the update button , no data is updated. I am a beginner , please tell me simple.
I have found the answer, and like to post here for newbies help.
The problem is , the datatable list is filled and used dynamically, so the data doesnot remain persistent, to be updated.
I need to update the list at runtime, and then finally persist it in database. For this i made an init method, to get the list into, and then used the getList() method to get the list.
I this way the updated, edited data is saved in the list. :)
I am having a pretty frustrating time trying to get values across components.
I am trying to do an address component that I can reuse, once for a residential address and once for a postal address. There is a selectOneCheck box which allows the user to specify that the residential address is the same as the postal address. I would like the the values of the first(residential address) component copied to the values of the second (postal address)component, then to disable the second component.
Here is my code for the composite component:
<composite:interface>
<composite:attribute name="addressLine1" required="true"
targets="addressLine1Text" />
<composite:attribute name="addressLine2" required="false"
targets="addressLine2Text" />
<composite:attribute name="addressLine3" required="false"
targets="addressLine3Text" />
<composite:attribute name="city" required="true" targets="cityText" />
<composite:attribute name="state" required="true" targets="stateText" />
<composite:attribute name="postCode" required="true"
targets="postCodeText" />
<composite:attribute name="styleClass" required="true" />
<composite:attribute name="disabled" required="true" />
<composite:attribute name="addressLine1Label" required="false"
targets="addressLine1Label" />
<composite:attribute name="addressLine2Label" required="false"
targets="addressLine2Label" />
<composite:attribute name="addressLine3Label" required="false"
targets="addressLine3Label" />
<composite:attribute name="cityLabel" required="false"
targets="cityLabel" />
<composite:attribute name="stateLabel" required="false"
targets="stateLabel" />
<composite:attribute name="postCodeLabel" required="false"
targets="postCodeLabel" />
<composite:implementation>
<composite:renderFacet name="heading"/>
<h:panelGrid columns="3">
<h:outputLabel id="addressLine1Label" for="addressLine1Text"
value="#{cc.attrs.addressLine1Label}" />
<h:inputText id="addressLine1Text" value="#{cc.attrs.addressLine1}" >
</h:inputText>
<h:message for="addressLine1Text" id="addressLine1Message" />
<h:outputLabel id="addressLine2Label" for="addressLine2Text"
value="#{cc.attrs.addressLine2Label}" />
<h:inputText id="addressLine2Text" value="#{cc.attrs.addressLine2}">
</h:inputText>
<h:message for="addressLine2Text" id="addressLine2Message" />
<h:outputLabel id="addressLine3Label" for="addressLine3Text"
value="#{cc.attrs.addressLine3Label}" />
<h:inputText id="addressLine3Text" value="#{cc.attrs.addressLine3}">
</h:inputText>
<h:message for="addressLine3Text" id="addressLine3Message" />
<h:outputLabel id="cityLabel" for="cityText"
value="#{cc.attrs.cityLabel}" />
<h:inputText id="cityText" value="#{cc.attrs.city}">
</h:inputText>
<h:message for="cityText" id="cityMessage" />
<h:outputLabel id="stateLabel" for="stateText"
value="#{cc.attrs.stateLabel}" />
<h:inputText id="stateText" value="#{cc.attrs.state}">
</h:inputText>
<h:message for="stateText" id="stateMessage" />
<h:outputLabel id="postCodeLabel" for="postCodeText"
value="#{cc.attrs.postCodeLabel}" />
<h:inputText id="postCodeText" value="#{cc.attrs.postCode}">
</h:inputText>
<h:message for="postCodeText" id="postCodeMessage" />
</h:panelGrid>
</composite:implementation>
Here is the the component in use :
<add:address
id="residentialAddress" styleClass="bold"
addressLine1="#{registrationBean.residentialAddress.addressLine1}"
addressLine2="#{registrationBean.residentialAddress.addressLine2}"
addressLine3="#{registrationBean.residentialAddress.addressLine3}"
city="#{registrationBean.residentialAddress.city}"
state="#{registrationBean.residentialAddress.state}"
postCode="#{registrationBean.residentialAddress.postCode}"
addressLine1Label="#{msgs.addressLine1}"
addressLine2Label="#{msgs.addressLine2}"
addressLine3Label="#{msgs.addressLine3}"
cityLabel="#{msgs.city}"
stateLabel="#{msgs.state}"
postCodeLabel="#{msgs.postCode}"
>
<f:facet name="heading">
<h:outputLabel value="#{msgs.residentialAddress}" />
</f:facet>
<f:converter for="add" converterId="myConvertor"/>
</add:address>
Here is the selectOneRadioButton:
<p:selectBooleanCheckbox
id="sameAsResidentialAddress"
itemLabel="#{msgs.sameAsResidentialAddress}"
valueChangeListener="#{registrationBean.sameAsResidentialAddress}"
>
<f:ajax execute="#form" render="postalAddress">
</f:ajax>
</p:selectBooleanCheckbox>
<h:message for="sameAsResidentialAddress"/>
Here is the component being resused for postal address:
<add:address id="postalAddress" styleClass="bold"
addressLine1="#{registrationBean.residentialAddress.addressLine1}"
addressLine2="#{registrationBean.postalAddress.addressLine2}"
addressLine3="#{registrationBean.postalAddress.addressLine3}"
city="#{registrationBean.postalAddress.city}"
state="#{registrationBean.postalAddress.state}"
postCode="#{registrationBean.postalAddress.postCode}"
addressLine1Label="#{msgs.addressLine1}"
addressLine2Label="#{msgs.addressLine2}"
addressLine3Label="#{msgs.addressLine3}" cityLabel="#{msgs.city}"
stateLabel="#{msgs.state}" postCodeLabel="#{msgs.postCode}"
rendered="#{!registrationBean.same}">
<f:facet name="heading">
<h:outputLabel value="#{msgs.postalAddress}" />
</f:facet>
<f:converter for="add" converterId="myConvertor"/>
</add:address>
The java code are a POJOs for Address and Registration. Registration has a valueChangeListener that sets a boolean to true if the sameAsResidentialAddress selectOneRadio is checked.
public void sameAsResidentialAddress(ValueChangeEvent event){
setSame((Boolean)event.getNewValue());
}
These components are on the same form named registration with no prepended id to them.
it roughly looks like this:
<h:form id="Registration">
<p:wizard>
<p:tab id ="address" title="Your Addresses">
<p:panel id="addresses">
<add:address id= "residentialAddress">
...
</add:address>
<p:selectBooleanCheckbox id="sameAsResidentialAddress">
...
</p:selectBooleanCheckbox>
<add:address id= "postalAddress">
...
</add:address>
</p:panel>
</p:tab>
</p:wizard>
</h:form>
I have tried my best to make my request as understandable as possible, and I hope you guys can understand what I am after. Please help me.
In the value change listener of the boolean check box you have to populate the postal address object which you are not doing. If both postal address and residential address are of the same type Address then you have to do
public void sameAsResidentialAddress(ValueChangeEvent event){
if((Boolean)event.getNewValue()) {
setSame((Boolean)event.getNewValue());
registrationBean.setPostalAddress(registrationBean.getResidentialAddress());
}
}
Hope this would help.
The problem was I did not completely understand the JSF lifecycle, I was updating my values the APPLY_REQUEST_VALUES phase instead of the INVOKE_APPLICATION phase. Also setting the postal address to the same object as the residential address is a bad idea because it end up with me not being able to update either one without affecting the other.
This works better.
public void sameAsResidentialAddress(ValueChangeEvent event) throws AbortProcessingException{
FacesContext context = FacesContext.getCurrentInstance();
if(context.getCurrentPhaseId() != PhaseId.INVOKE_APPLICATION){
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
if ((Boolean)event.getNewValue()){
this.setSame(true);
this.getPostalAddress().setAddressLine1(getResidentialAddress().getAddressLine1());
this.getPostalAddress().setAddressLine2(getResidentialAddress().getAddressLine2());
this.getPostalAddress().setAddressLine3(getResidentialAddress().getAddressLine3());
this.getPostalAddress().setCity(getResidentialAddress().getCity());
this.getPostalAddress().setState(getResidentialAddress().getState());
this.getPostalAddress().setPostCode(getResidentialAddress().getPostCode());
System.out.println("Value was true");
System.out.println("Postal Address " + getPostalAddress());
System.out.println("Residential Address " + getResidentialAddress());
}else{
setPostalAddress(new Address());
}
}
I'm using a tabView-Element of primefaces. The first tab points to the "Home" element the second one to a registration form. The registration form is validated. The problem is, when the form is validated the user is redirect to the home tab. When the user navigates back, he can see the validation errors.
This seems to be a more or less common problem, but I did not find a proper solution. I tried out Oleg Varaksin suggestion to prevent a user switching tabs when a form validation failed, but my problem starts earlier.
I tried to fiddle aorund with the onTabChange event but with no success. Is there a mistake in my code or how can I approach may probelm? I would welcome a push in the right direction.
<p:tabView id="mainTabView">
<p:tab title="Startseite" id="startPage">
<p:layout style="min-width:400px;min-height:400px;border:none !important"
id="layout_login">
<p:layoutUnit position="west" size="305">
<p:panel>
<h:form id="loginForm">
<p:panelGrid columns="2" styleClass="gridWithNoBorders reducedFontSize">
<p:outputLabel value="Benutzername:" />
<p:inputText size="14" value="#{data.username}" />
<p:outputLabel value="Passwort:" />
<p:inputText size="14" value="#{data.loginPassword}" />
</p:panelGrid>
<p:separator />
<h:commandButton styleClass="reducedFontSize" value="Anmelden" />
</h:form>
</p:panel>
</p:layoutUnit>
<p:layoutUnit position="center">
<p:panel>
Lorem ipsum dolor sit amet(...)
</p:panel>
</p:layoutUnit>
</p:layout>
</p:tab>
<p:tab id="registrationPage" title="#{ivy.cms.co('/Translations/Registration/tabTitleRegistration')}" >
<h:form id="registrationForm">
<p:panel header="#{ivy.cms.co('/Translations/Registration/panelHeaderRegistration')}">
<p:panelGrid columns="3">
<p:outputLabel value="#{ivy.cms.co('/Translations/Registration/labelEmail')}" />
<p:inputText value="#{data.email}" id="email1" required="true" requiredMessage="#{ivy.cms.co('/Translations/Registration/enterEmailAddress')}">
<f:validator validatorId="EmailValidator" />
<f:validator validatorId="EmailCompareValidator" />
</p:inputText>
<p:message for="email1" />
<p:outputLabel value="#{ivy.cms.co('/Translations/Registration/labelRepeatEmail')}" />
<p:inputText value="#{data.emailConfirm}" id="email2" required="true" requiredMessage="#{ivy.cms.co('/Translations/Registration/repeatMailAddress')}">
<f:validator validatorId="EmailValidator" />
</p:inputText>
<p:message for="email2"/>
<p:outputLabel value="#{ivy.cms.co('/Translations/Registration/labelPrename')}" />
<p:inputText value="#{data.prename}" id="prename" required="true" requiredMessage="#{ivy.cms.co('/Translations/Registration/enterPrename')}"/>
<p:message for="prename"/>
<p:outputLabel value="#{ivy.cms.co('/Translations/Registration/labelSurname')}" />
<p:inputText value="#{data.surname}" id="surname" required="true" requiredMessage="#{ivy.cms.co('/Translations/Registration/enterSurname')}"/>
<p:message for="surname"/>
<p:outputLabel value="#{ivy.cms.co('/Translations/Registration/labelPassword')}" />
<p:password id="pwd1" value="#{data.registrationPassword}" match="pwd2"
required="true" feedback="true" requiredMessage="#{ivy.cms.co('/Translations/Registration/enterPassword')}"
weakLabel="#{ivy.cms.co('/Translations/Registration/passwordWeak')}"
goodLabel="#{ivy.cms.co('/Translations/Registration/passwordMedium')}"
strongLabel="#{ivy.cms.co('/Translations/Registration/passwordStrong')}" />
<p:message for="pwd1"/>
<p:outputLabel value="#{ivy.cms.co('/Translations/Registration/labelRepeatPassword')}" />
<p:password id="pwd2" value="#{data.confirmPassword}" required="true" requiredMessage="#{ivy.cms.co('/Translations/Registration/repeatPassword')}"/>
<p:message for="pwd2"/>
<h:commandButton value="#{ivy.cms.co('/Translations/Registration/finishRegistration')}" actionListener="#{logic.startRegistration}" >
<p:ajax event="click" listener="#{logic.startRegistration}"/>
</h:commandButton>
</p:panelGrid>
</p:panel>
</h:form>
</p:tab>
</p:tabView>
I had to combine the binding and ajax to achieve my goal. It seems that the activeIndex is resetted after the form validation (?) therefore it is not honored after submitting the form. I've used the approach that was suggested by Steves to use the binding property. So here is the working code:
xhtml:
<p:layoutUnit position="center">
<p:tabView id="mainTabView" binding="#{tabIndexHelper.messagesTab}">
<p:ajax event="tabChange" listener="#{tabIndexHelper.onTabChange}" />
<p:tab title="Startseite" id="startPage">
<ui:include src="HomePage.xhtml" />
</p:tab>
<p:tab id="registrationPage" title="#{ivy.cms.co('/Translations/Registration/tabTitleRegistration')}" >
<ui:include src="RegisterPage.xhtml" />
</p:tab>
</p:tabView>
</p:layoutUnit>
And the backing bean:
private TabView messagesTab = new TabView();
public TabView getMessagesTab () {
return messagesTab;
}
public void setMessagesTab(TabView messagesTab ) {
this.messagesTab = messagesTab;
}
public void onTabChange(TabChangeEvent event) {
TabView tabView = (TabView) event.getComponent();
int activeIndex = tabView.getChildren().indexOf(event.getTab());
this.messagesTab.setActiveIndex(activeIndex);
}
Thanks for support. :)
You need to fix the current tab selected if you don't the update or validation should reset the tabview with default tab selected(the first one).
So you could use activeIndex attribut from tabView :
<p:tabView activeIndex="#{bean.activeIndex}"/>
From Primeface User Guide:
activeIndex is an Integer with default value 0. Index of the active tab.
And create an event for set this var like that :
<p:ajax event="tabChange" listener="#{bean.onTabChange}"/>