I use JavaEE 7 (JSF 2.2, Bean Validation 1.1...) and primefaces 5.1 in WildFly 8.1 runtime
I want to use different validation groups according to the pressed button. A save button associated with a small number of constraints and a submit button associated with a larger number of constraints.
The bean validation groups seem to be what I need but I have some issues with the web interface.
I wan't that the invalid inputs appear in red according to the validation mode : save or submit
So I made 3 interfaces :
public interface LifeCycleValidation {}
public interface Save extends LifeCycleValidation {}
public interface Submit extends Save {}
I annotate fields using BeanVal with the appropiate group in the model object
#Size(min=3, max = 300, groups = Save.class)
#NotNull(groups = Save.class)
private String title ;
#Size(min = 3, max = 5, groups = Submit.class)
private List<String> keywords ;
I made some methods in the JSF managed bean
private final String formIdPrefix = "bookEditForm:" ;
public void save() {
save(Save.class) ;
}
public void submit() {
save(Submit.class) ;
}
private void save(Class<? extends LifeCycleValidation> groupClass) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory() ;
Validator validator = factory.getValidator();
Set<ConstraintViolation<Book>> violations = validator.validate(this, groupClass);
violations.stream()
.forEach(violation -> addErrorMessage(formIdPrefix+violation.getPropertyPath().toString(), violation.getMessage()));
if(violations.isEmpty()) {
// save
addInfoMessage("","sucess") ;
} else {
addErrorMessage("",violations.size()+" error(s)") ;
}
}
private void addErrorMessage(String id, String msg) {
addMessage(id,FacesMessage.SEVERITY_ERROR,"Error",msg) ;
}
private void addInfoMessage(String id, String msg) {
addMessage(id,FacesMessage.SEVERITY_INFO,"Info",msg) ;
}
private void addMessage(String clientId, FacesMessage.Severity severity, String summary, String detail) {
FacesMessage message = new FacesMessage(severity, summary, detail);
FacesContext.getCurrentInstance().addMessage(clientId, message);
}
The messages display correctly if the id of the input correspond to the path of the property but the input aren't red
<h:form id="bookEditForm">
<p:messages showDetail="true" showSummary="true"/>
<p:panelGrid columns="3">
<p:outputLabel value="title" for="title"/>
<p:inputText value="#{book.title}" id="title"/>
<p:message showDetail="true" showSummary="true" for="title"/>
<p:outputLabel value="keywords" for="keywords"/>
<p:inputText value="#{book.keywords}" id="keywords" converter="converter.ListString"/>
<p:message showDetail="true" showSummary="true" for="keywords"/>
</p:panelGrid>
<p:commandButton value="save" action="#{book.save()}" update="#form"/>
<p:commandButton value="submit" action="#{book.submit()}" update="#form"/>
</h:form>
(in my exemple the model and the controller is in the same class, it was just a test)
I try an other solution using f:validateBean validationGroups
So I made ValidationMode enum:
public enum ValidationMode {
SAVE(Save.class), SUBMIT(Submit.class);
public final Class<? extends LifeCycleValidation> cl ;
private ValidationMode(Class<? extends LifeCycleValidation> cl) {
this.cl = cl ;
}
}
and put it in the JSF managed bean:
private ValidationMode validationMode ;
public void setValidationMode(String validationModeTitle) {
this.validationMode = ValidationMode.valueOf(validationModeTitle);
}
public String getValidationGroups() {
if(validationMode==null) {
return ValidationMode.SAVE.cl.getCanonicalName() ;
}
return validationMode.cl.getCanonicalName() ;
}
and try to set the appropriate mode in the actionListener of ther commandButton
<h:form id="bookEditForm">
<p:messages showDetail="true" showSummary="true"/>
<p:panelGrid columns="3">
<p:outputLabel value="title" for="title"/>
<p:inputText value="#{book.title}" id="title">
<f:validateBean validationGroups="#{book.validationGroups}"/>
</p:inputText>
<p:message showDetail="true" showSummary="true" for="title"/>
<p:outputLabel value="keywords" for="keywords"/>
<p:inputText value="#{book.keywords}" id="keywords" converter="converter.ListString">
<f:validateBean validationGroups="#{book.validationGroups}"/>
</p:inputText>
<p:message showDetail="true" showSummary="true" for="keywords"/>
</p:panelGrid>
<p:commandButton value="save" action="#{book.save()}" actionListener="#{book.setValidationMode('SAVE')}" update="#form"/>
<p:commandButton value="submit" action="#{book.submit()}" actionListener="#{book.setValidationMode('SUBMIT')}" update="#form"/>
</h:form>
but that doesn't work
The I think of writing my own jsf validator but I don't know how to implement the validator to validate the field according to the right group
I finnaly found something, I trigger the setValidationMode when an onmouseover occured like that the validation mode is set before the action: save or submit is called
<h:panelGroup layout="span">
<p:ajax event="mouseover" listener="#{book.setValidationMode('SAVE')}"/>
<p:commandButton value="save" action="#{book.save()}" update="#form"/>
</h:panelGroup>
<h:panelGroup layout="span">
<p:ajax event="mouseover" listener="#{book.setValidationMode('SUBMIT')}"/>
<p:commandButton value="submit" action="#{book.submit()}" update="#form"/>
</h:panelGroup>
so you have nothing to do in the controller
private ValidationMode validationMode = ValidationMode.SAVE ;
public void setValidationMode(String validationModeTitle) {
this.validationMode = ValidationMode.valueOf(validationModeTitle);
}
public String getValidationGroups() {
return validationMode.cl.getCanonicalName() ;
}
public void save() {
// save
addInfoMessage("","saved") ;
}
public void submit() {
// submit
addInfoMessage("","submited") ;
}
Edit
here is the clean and complete MVC solution with the progressbar calculated in bonus :
the view:
<h:form id="bookEditForm">
<p:progressBar value="#{bookBean.progress}" labelTemplate="{value}%" id="progress"/>
<p:messages showDetail="true" showSummary="true"/>
<p:panelGrid columns="3">
<p:outputLabel value="title" for="title"/>
<p:inputText value="#{bookBean.book.title}" id="title">
<f:validateBean validationGroups="#{bookBean.validationGroups}"/>
</p:inputText>
<p:message showDetail="true" showSummary="true" for="title"/>
<p:outputLabel value="keywords" for="keywords"/>
<p:inputText value="#{bookBean.book.keywords}" id="keywords" converter="converter.ListString">
<f:validateBean validationGroups="#{bookBean.validationGroups}"/>
</p:inputText>
<p:message showDetail="true" showSummary="true" for="keywords"/>
</p:panelGrid>
<h:panelGroup layout="span">
<p:ajax event="mouseover" listener="#{bookBean.setValidationMode('SAVE')}"/>
<p:commandButton value="save" action="#{bookBean.save()}" update="#form"/>
</h:panelGroup>
<h:panelGroup layout="span">
<p:ajax event="mouseover" listener="#{bookBean.setValidationMode('SUBMIT')}"/>
<p:commandButton value="submit" action="#{bookBean.submit()}" update="#form"/>
</h:panelGroup>
</h:form>
the controller:
#Named
#ViewScoped
public class BookBean implements Serializable {
private ValidationMode validationMode = ValidationMode.SAVE;
private Book book ;
public BookView() {
book = new Book() ;
}
public void setValidationMode(String validationModeTitle) {
this.validationMode = ValidationMode.valueOf(validationModeTitle);
}
public String getValidationGroups() {
return validationMode.cl.getCanonicalName() ;
}
public Book getBook() {
return book;
}
public void save() {
// save...
addMessage("",FacesMessage.SEVERITY_INFO,"Success","Infos saved") ;
}
public void submit() {
//submit...
addMessage("",FacesMessage.SEVERITY_INFO,"Success","Infos submitted") ;
}
private void addMessage(String clientId, FacesMessage.Severity severity, String summary, String detail) {
FacesMessage message = new FacesMessage(severity, summary, detail);
FacesContext.getCurrentInstance().addMessage(clientId, message);
}
public int getProgress() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory() ;
Validator validator = factory.getValidator();
int nbConstraints = validator.getConstraintsForClass(Book.class).getConstrainedProperties().size() ;
int nbViolations = validator.validate(book, Submit.class).size();
return 100 - (nbViolations*100) / (nbConstraints) ;
}
}
the model:
public class Book implements Serializable {
#NotNull(groups = Save.class)
#Size(min=1, max = 140, groups = Save.class)
private String title ;
#NotNull(groups = Submit.class)
#Size(min = 3, max = 5, groups = Submit.class)
private List<String> keywords ;
// getters and setters
}
ValidationMode, LifeCycleValidation, Save and Submit are the same as in the question
And OmniFaces seems to have a nice solution :
http://showcase.omnifaces.org/validators/validateBean
Could be interesting...
Related
I am unable to pass and then retrieve variable from a backing bean. My add() function is called when a tree node is selected:
public void add(TreeNode selectedTreeNode) {
setMyid(((MyClass) selectedTreeNode.getData()).getId());
System.out.println("id : " + getMyid());
RequestContext.getCurrentInstance().execute("PF('dlgVar').show()");
}
public String saveAction() {
String myid = FacesContext.getCurrentInstance().
getExternalContext().getRequestParameterMap().get("myid");
System.out.println("myid : " + myid);
}
public void setMyid(String myid) {
this.myid = myid;
}
public String getMyid() {
return myid;
}
The dialog is:
<p:dialog id="dlgId" widgetVar="dlgVar" dynamic="true">
<h:form>
<h:panelGrid columns="1">
<h:outputLabel for="nametext" value="Name" />
<p:inputText id="nametext" value="#{myBean.name}" />
</h:panelGrid>
<p:commandButton value="Save" actionListener="#{myBean.saveAction}" >
<f:param name="myid" value="#{myBean.myid}" />
</p:commandButton>
</h:form>
</p:dialog>
The id printed in saveAction() is null but it is not null when set in add().
How can I set myid from backing bean so that it is correctly passed back to saveAction()?
I have a simple form, with some input and a selectonemenu:
<h:panelGroup id="Client">
<h:form id="formClient">
<p:panelGrid columns="3" layout="grid"
columnClasses="labelWidth, ui-grid-col-3">
<p:outputLabel value="CIN:" for="txtCin" />
<h:panelGrid columns="2">
<p:inputText value="#{clientBean.client.identifiant}" id="txtCin"></p:inputText>
<p:commandButton value="Search" process="#parent"
styleClass="orangeButton" update="formClient"
style="margin-top: -10px;" action="#{clientBean.rechercher()}"></p:commandButton>
</h:panelGrid>
<p:message for="txtCin" />
<p:outputLabel value="Nom:" for="txtNom" />
<p:inputText id="txtNom" styleClass="form-control"
value="#{clientBean.client.nomClient}" required="true"
requiredMessage="Le nom est obligatoire" />
<p:message for="txtNom" />
<p:outputLabel value="Type de voie:" for="txtVoie" />
<p:selectOneMenu styleClass="form-control"
value="#{clientBean.client.typeVoie}" id="txtVoie">
<f:selectItem itemLabel="Selectionnez voie..." itemValue="" />
<f:selectItems value="#{clientBean.typeVoies}" var="typeVoie" itemLabel="#{typeVoie.libelle}" itemValue="#{typeVoie}" />
</p:selectOneMenu>
<p:message for="txtVoie" />
<p:outputPanel></p:outputPanel>
<p:outputPanel>
<p:commandButton value="Annuler" update="formClient"
styleClass="redButton" process="#this"
actionListener="#{clientBean.cancel()}" />
<p:commandButton ajax="false" value="Suivant"
styleClass="greenButton" action="Devis?faces-redirect=true"></p:commandButton>
</p:outputPanel>
</p:panelGrid>
</h:form>
</h:panelGroup>
As you see here i have some fields that are a required, and a button to cancel (empties) the form:
#ManagedBean(name = "clientBean")
#SessionScoped
public class ClientBean implements Serializable {
#EJB
private IClientDAO clientDAO;
#EJB
private ITypeVoieDAO typeVoieDAO;
private List<TypeVoie> typeVoies;
private static final long serialVersionUID = -3324864097586374969L;
private Client client = new Client();
#PostConstruct
public void init(){
typeVoies = typeVoieDAO.findAll();
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public void rechercher(){
if(client != null && client.getIdentifiant() != null){
System.out.println(client.getIdentifiant());
client = clientDAO.findByIdentifiant(client.getIdentifiant());
if(client == null){
cancel();
}
}
}
public void cancel(){
client = new Client();
System.out.println(typeVoies);
}
public String navigateToClientPage(){
rechercher();
return "client?faces-redirect=true";
}
public List<TypeVoie> getTypeVoies() {
return typeVoies;
}
public void setTypeVoies(List<TypeVoie> typeVoies) {
this.typeVoies = typeVoies;
}
}
At the page loads, the selectonemenu loads perfectly, but when i click cancel, the selectonemenu gets emptied, even when i "search" for a client, and updates the form, all the other fields are filled properly, but the selectonemenu gets completely empty.
Using JSF 2.1 and primefaces 6.0
UPDATE:
Added a converter, but nothing change ...
Make sure you dont empty typeVoies list at some point on your backingbean. And if you can share your full java class, you might get more accurate help.
I have a p:inputTextarea and I need the value of it while processing the form. It turned out that every time I submit the form I get all the values except the one from the textarea. #{xyzUI.description} is a String object with regular getters and setters.
<ui:composition>
<h:form id="form1">
<p:panel rendered="...">
<p:panel id="formPanel">
<p:panelGrid columns="2" cellpadding="5">
<!-- other form elements -->
<p:outputLabel>Description:</p:outputLabel>
<p:inputTextarea value="#{xyzUI.description}" style="width: 350px;" counter="display" counterTemplate="{0} characters remaining" maxlength="2000" autoResize="true" rows="4" />
<h:panelGroup />
<h:outputText id="display" />
</p:panelGrid>
<p:commandButton rendered="#{not xyzUI.noChange}" action="#{xyzUI.submitForm}" update="formPanel" ajax="true" value="Apply" >
<p:ajax update="formPanel"></p:ajax>
</p:commandButton>
</p:panel>
</p:panel>
</h:form>
<ui:composition>
In my backing bean the value is always "". I don't know what's wrong.
public void submitForm()
{
...
tmp.setDescription(description); // String is always "" while debugging
myList.add(tmp);
RequestContext.getCurrentInstance().update("content");
}
I ran your code locally and discovered the issue. In the command button, remove the p:ajax call.
PrimeFaces command buttons are ajax enabled by default.
So change this:
<p:commandButton rendered="#{not xyzUI.noChange}" action="#{xyzUI.submitForm}" update="formPanel" ajax="true" value="Apply" >
<p:ajax update="formPanel"></p:ajax>
</p:commandButton>
To this:
<p:commandButton rendered="#{not xyzUI.noChange}" action="#{xyzUI.submitForm}" update="formPanel" value="Apply" />
My backing bean for reference
#ManagedBean
#ViewScoped
public class xyzUI implements Serializable{
private static final long serialVersionUID = 6259024062406526022L;
private String description;
private boolean noChange = false;
public xyzUI(){
}
public void submitForm(){
System.out.println(description);
}
public boolean isNoChange() {
return noChange;
}
public void setNoChange(boolean noChange) {
this.noChange = noChange;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
I've been strugling with an issue I can't find the way to solve it and I can't find anything related on the web.
I'm using Netbeans with Primefaces to develop a JSF web app.
Everything works fine except that sometimes the call to the actionlisteners is being done several times.
For example this is my JSF page with primefaces:
<h:body>
<ui:composition template="home.xhtml">
<ui:define name="content">
<h2>Administración de alertas SMS</h2>
<p:panel id="display">
<p:selectBooleanCheckbox itemLabel="Enviar alertas SMS" value="#{smsConfigBean.alertsEnabled}"/>
<p>
<h:outputText value="Mensaje de Texto: " /><br /><br />
<p:inputTextarea rows="5" cols="50" counterTemplate="{0} caracteres restantes." counter="counter" maxlength="160" value="#{smsConfigBean.smsMessage}" id="smsMessage"/>
<br />
<h:outputText id="counter" />
</p>
<p>
<h:outputText value="Dispositivo de envio SMS: " />
<p:selectOneRadio id="options" value="#{smsConfigBean.usePhone}">
<f:selectItem itemLabel="Modem USB" itemValue="false" />
<f:selectItem itemLabel="Telefono Android" itemValue="true" />
</p:selectOneRadio>
</p>
<br />
<p:tabView id="tabView">
<p:tab id="tab1" title="Modem USB">
<h:panelGrid id="modemGrid" columns="2" cellpadding="4">
<h:outputText value="Puerto: " />
<p:inputText id="port" value="#{smsConfigBean.port}"/>
<h:outputText value="Bit Rate (Opcional): " />
<p:inputText id="bitRate" value="#{smsConfigBean.bitRate}"/>
<h:outputText value="Nombre de modem (Opcional): " />
<p:inputText id="modemName" value="#{smsConfigBean.modemName}"/>
<h:outputText value="PIN: " />
<p:inputText id="pin" value="#{smsConfigBean.modemPin}"/>
<h:outputText value="Centro de Mensajes: " />
<p:inputText id="smsc" value="#{smsConfigBean.SMSC}"/>
</h:panelGrid>
</p:tab>
<p:tab id="tab2" title="Telefono Android">
<h:panelGrid id="phoneGrid" columns="2" cellpadding="4">
<h:outputText value="Path ADB:" />
<p:inputText id="adbPath" value="#{smsConfigBean.adbPath}"/>
<h:outputText value="Directorio de Configuracion:" />
<p:inputText id="configPath" value="#{smsConfigBean.configPath}"/>
<h:outputText value="Modo de conexion " />
<p:selectOneRadio id="connectOptions" value="#{smsConfigBean.useWifi}">
<f:selectItem itemLabel="USB" itemValue="false"/>
<f:selectItem itemLabel="WiFi" itemValue="true" />
</p:selectOneRadio>
<h:outputText value="Direccion IP (Solo para WiFi): " />
<p:inputText id="ipDir" value="#{smsConfigBean.ipDir}"/>
</h:panelGrid>
</p:tab>
</p:tabView>
</p:panel>
<br />
<p:commandButton id="saveSmsAlerts" value="Guardar" update="messages" action="#{smsConfigBean.saveChanges}" actionListener="#{smsConfigBean.saveChanges}"/>
</ui:define>
</ui:composition>
</h:body>
And this is my backend bean:
package Beans;
import helpers.Global; import javax.faces.bean.ManagedBean; import
javax.faces.bean.SessionScoped;
#ManagedBean #SessionScoped public class SmsConfigBean {
private Boolean alertsEnabled;
private Boolean usePhone;
private Boolean useWifi;
private String port;
private int bitRate;
private String modemName;
private String modemPin;
private String SMSC;
private String adbPath;
private String configPath;
private String ipDir;
private String smsMessage;
public SmsConfigBean() {
alertsEnabled = Global.getAlertsEnabled();
port = Global.getPort();
bitRate = Global.getBitRate();
modemName = Global.getModemName();
modemPin = Global.getModemPin();
SMSC = Global.getSMSC();
usePhone = Global.getUsePhone();
adbPath = Global.getAdbPath();
configPath = Global.getConfigPath();
useWifi = Global.getUseWifi();
ipDir = Global.getIpDir();
smsMessage = Global.getSmsMessage();
}
public Boolean getAlertsEnabled() {
return alertsEnabled;
}
public void setAlertsEnabled(Boolean alertsEnabled) {
this.alertsEnabled = alertsEnabled;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public int getBitRate() {
return bitRate;
}
public void setBitRate(int bitRate) {
this.bitRate = bitRate;
}
public String getModemName() {
return modemName;
}
public void setModemName(String modemName) {
this.modemName = modemName;
}
public String getModemPin() {
return modemPin;
}
public void setModemPin(String modemPin) {
this.modemPin = modemPin;
}
public String getSMSC() {
return SMSC;
}
public void setSMSC(String SMSC) {
this.SMSC = SMSC;
}
public Boolean getUsePhone() {
return usePhone;
}
public void setUsePhone(Boolean usePhone) {
this.usePhone = usePhone;
}
public String getAdbPath() {
return adbPath;
}
public void setAdbPath(String adbPath) {
this.adbPath = adbPath;
}
public String getConfigPath() {
return configPath;
}
public void setConfigPath(String configPath) {
this.configPath = configPath;
}
public Boolean getUseWifi() {
return useWifi;
}
public void setUseWifi(Boolean useWifi) {
this.useWifi = useWifi;
}
public String getIpDir() {
return ipDir;
}
public void setIpDir(String ipDir) {
this.ipDir = ipDir;
}
public String getSmsMessage() {
return smsMessage;
}
public void setSmsMessage(String smsMessage) {
this.smsMessage = smsMessage;
}
public void saveChanges(){
Global.setSmsMessage(smsMessage);
Global.setIpDir(ipDir);
Global.setUseWifi(useWifi);
Global.setConfigPath(configPath);
Global.setAdbPath(adbPath);
Global.setUsePhone(usePhone);
Global.setSMSC(SMSC);
Global.setModemPin(modemPin);
Global.setModemName(modemName);
Global.setBitRate(bitRate);
Global.setPort(port);
Global.setAlertsEnabled(alertsEnabled);
Global.sendInfoResponseMessage("Cambios guardados con exito");
}
}
The problem is that when saving the changes of this form by hitting the commandButton 'saveSmsAlerts' the call is being made twice. Resulting in the growl message to be shown twice too.
(You won't see the growl component because it was defined in the template)
This happens also in another page that I did for the same app that uploads a file using fileuploader. The file is uploaded 4 times!!
I'm using chrome to test the application and netbeans to develop it.
You should remove one of action or actionListener attribute.
<p:commandButton id="saveSmsAlerts" value="Guardar" update="messages" action="#{smsConfigBean.saveChanges}"/>
if you remove action attribute you should change the action method signature
<p:commandButton id="saveSmsAlerts" value="Guardar" update="messages" actionListener="#{smsConfigBean.saveChanges}"/>
Like this
public void saveChanges(ActionEvent e){
...
}
here is the difference between action and actionListener
Differences between action and actionListener
Anyone know of a way to assign the value of a p:inputText so it displays correctly in a dialog window but only update a change in the value from a commandButton action instead of a dynamic set method of the value in the backing bean. Have the users add a step and it shows up in the ring then they can click the individual steps, but I want them to be able to update the step info only through the update step button, not by just changing the field and closing the dialog? Built-in method would be prefer, I know I can code around, but trying not to.
Thanks in advance....
<p:ajaxStatus onstart="statusDialog.show();" onsuccess="statusDialog.hide();"/>
<p:dialog modal="true" widgetVar="statusDialog" header="Status"
draggable="false" closable="false">
<p:graphicImage value="/resources/images/ajaxloadingbar.gif" />
</p:dialog>
<h:form id="form">
<p:panel header="Setup System" >
<p:selectOneMenu value="#{groups.selected_sys_code}" id="systems" rendered="#{utility.systemDD}">
<f:selectItem itemLabel="Choose System" itemValue="" />
<f:selectItems value="#{supportBean.access_system_codes}"/>
<p:ajax listener="#{groups.valueChanged}" event="valueChange" render="systemForm" execute="#all"/>
</p:selectOneMenu>
<h:panelGroup id="systemForm" >
<p:panel id="panel" header="Step Details">
<p:messages id="msgs"/>
<h:panelGrid columns="2" columnClasses="label, value" styleClass="grid">
<p:panelGrid columns="2" styleClass="veaGrid">
<h:outputLabel for="name" value="Name:"/>
<p:inputText id="name" value="#{setup.name}" label="Name" required="true"/>
<h:outputLabel for="desc" value="Description:"/>
<p:inputText id="desc" value="#{setup.description}" label="Description" required="true"/>
<h:outputLabel for="email" value="Email For Group Responsible:"/>
<p:inputText id="email" value="#{setup.emailResp}" label="Email" required="true"/>
<h:outputLabel for="process" value="Process:"/>
<p:inputText id="process" value="#{setup.process}" label="Process" required="true"/>
</p:panelGrid>
</h:panelGrid>
<p:commandButton value="Add Step" update="panel,stepsRing" actionListener="#{setup.setSteps}" process="#form" >
</p:commandButton>
<p:commandButton value="Submit All Steps" actionListener="setup.submitSteps">
</p:commandButton>
</p:panel>
</h:panelGroup>
<h:panelGroup id="stepsRing" >
<p:panel header="Steps">
<p:ring id="basic" value="#{setup.steps}" var="step" >
<p:column>
<p:outputPanel/>
<p:outputPanel style="text-align:center;" layout="block" >
Step #{step.sequence}
<br/>
<p:commandButton update=":form:detail" title="View" oncomplete="dlg.show()" value="Details" >
<f:setPropertyActionListener value="#{step}" target="#{setup.selectedStep}" />
</p:commandButton>
</p:outputPanel>
</p:column>
</p:ring>
</p:panel>
</h:panelGroup>
<p:dialog id="dialog" widgetVar="dlg" showEffect="fade" hideEffect="fade" modal="true" width="300" >
<p:outputPanel id="detail" style="text-align:center;" layout="block">
<h:panelGrid columns="2" cellpadding="5" rendered="#{not empty setup.selectedStep}">
<f:facet name="header">
Step #{setup.selectedStep.sequence}
</f:facet>
<h:outputText value="Name: " />
<p:inputText id="name2" value="#{setup.selectedStep.name}" />
<h:outputText value="Description: " />
<p:inputText id="desc2" value="#{setup.selectedStep.description}" />
<h:outputText value="Email: " />
<p:inputText id="email2" value="#{setup.selectedStep.emailResp}"/>
<h:outputText value="Process: " />
<p:inputText id="process2" value="#{setup.selectedStep.process}"/>
<p:commandButton update="stepsRing" actionListener="#{setup.removeStep}" title="Remove" oncomplete="dlg.hide()" value="Remove Step" >
<f:setPropertyActionListener value="#{step}" target="#{setup.selectedStep}" />
</p:commandButton>
<p:commandButton update="stepsRing" process="#form" actionListener="#{setup.updateStep}" title="Update" value="Update Step" >
<f:setPropertyActionListener value="#{step}" target="#{setup.selectedStep}" />
</p:commandButton>
</h:panelGrid>
</p:outputPanel>
</p:dialog>
</p:panel>
</h:form>
BackingBean
#ManagedBean(name="setup")
#ViewScoped
public class WorkStepSetupSystemBean implements Serializable{
private WorkSetup step;
public ArrayList <WorkSetup> steps=new ArrayList <WorkSetup> ();
private WorkSetup ws;
private String system="test1";
private String emailResp;
private String process;
private String name;
private String description;
private Integer sequence;
private String email2;
private String process2;
private String name2;
private String desc2;
private WorkSetup selectedStep;
public WorkStepSetupSystemBean(){
}
public String getDesc2() {
return desc2;
}
public String getEmail2() {
return email2;
}
public String getName2() {
return name2;
}
public String getProcess2() {
return process2;
}
public WorkSetup getSelectedStep() {
return selectedStep;
}
public ArrayList<WorkSetup> getSteps() {
return steps;
}
public WorkSetup getStep() {
return step;
}
public void setSteps(ActionEvent event) {
step= new WorkSetup();
step.setName(name);
step.setEmailResp(emailResp);
step.setDescription(description);
step.setSystem(system);
step.setProcess(process);
step.setSequence(steps.size()+1);
steps.add(step);
return;
}
public void setStep(ArrayList<WorkSetup> steps) {
this.steps = steps;
}
public Integer getSequence() {
return sequence;
}
public String getDescription() {
return description;
}
public String getEmailResp() {
return emailResp;
}
public String getName() {
return name;
}
public String getProcess() {
return process;
}
public String getSystem() {
return system;
}
public void setDescription(String description) {
this.description = description;
}
public void setEmailResp(String emailResp) {
this.emailResp = emailResp;
}
public void setName(String name) {
this.name = name;
}
public void setProcess(String process) {
this.process = process;
}
public void setSequence(Integer sequence) {
this.sequence = sequence;
}
public void setSystem(String system) {
this.system = system;
}
public void setDesc2(String desc2) {
this.desc2 = desc2;
}
public void setEmail2(String email2) {
this.email2 = email2;
}
public void setName2(String name2) {
this.name2 = name2;
}
public void setProcess2(String process2) {
this.process2 = process2;
}
public void setSelectedStep(WorkSetup selectedStep) {
this.selectedStep = selectedStep;
}
public void removeStep(ActionEvent event) {
steps.remove(steps.indexOf(this.selectedStep));
for(int i=0;i<steps.size();i++){
steps.get(i).setSequence(i+1);
}
}
public void updateStep(ActionEvent event) {
step=steps.get(steps.indexOf(this.selectedStep));
step.setName(name2);
step.setEmailResp(email2);
step.setDescription(desc2);
step.setSystem(system);
}
}
Ended up using
<p:inplace id="inplaceName" >
<p:inputText id="name2" value="#{setup.selectedStep.name}" />
<p:tooltip for="inplaceName" value="Click here to edit"/>
</p:inplace>
without the AJAX option