Validation errors in dialog not updating after failed submit in JSF - ajax

So I click a button which opens a dialog. Inside this dialog I want to fill out information in a form and submit and save it. Some of the inputTexts need to be required in order to submit. So I use the required="true" attribute. It stops the submission, but it does not update the field with a red outline of everything. Now, if I hit cancel and open up the dialog again it will show the fields that failed validation with a red outline!
I thought I could solve this by manually updating the dialog whenever I try to submit the form. This just causes the dialog to close though instead of staying open and refreshing the dialog to show the validation failures.
This is the dialog, when I hit the save button is when I submit the form
<h:form>
<p:dialog header="#{headerValue}" widgetVar="#{uniqueId}_editDialog"
modal="false" showEffect="fade" styleClass="dialogGrid"
dynamic="true" draggable="true" resizable="false">
<p:outputPanel style="text-align:center;" layout="block">
<p:messages autoUpdate="true"/>
<ui:insert name="editContent">
Edit Content Here. Use 'selectedModel.whatever'
</ui:insert>
<p:panelGrid columns="3" styleClass="buttonGrid">
<ui:insert name="saveButton">
<p:commandButton iconPos="left" value="#{msg.save}"
rendered="#{'VIEW' != selectedModel.viewState}"
process="#widgetVar(#{uniqueId}_editDialog)"
action="#{adapterInjector.add(modelList, selectedModel)}"
update="#widgetVar(#{uniqueId}_itemsDataList) #widgetVar(#{uniqueId}_addButton) #widgetVar(#{uniqueId}_editDialog)"
oncomplete="if(!args.validationFailed) PF('#{uniqueId}_editDialog').hide()"
partialSubmit="true" validateClient="true">
</p:commandButton>
</ui:insert>
<p:commandButton iconPos="right" value="#{msg.cancel}"
process="#this" oncomplete="PF('#{uniqueId}_editDialog').hide()"
resetValues="true" partialSubmit="true">
</p:commandButton>
</p:panelGrid>
</p:outputPanel>
</p:dialog>
</h:form>
This is an inserted component which has the required attribute
<p:selectOneMenu id="licenseCert"
value="#{selectedModel.selectedLicenseCert}" filter="true"
required="true">
<f:selectItem itemLabel="#{msg.selectOne}" itemValue=""
noSelectionOption="true" />
<f:selectItems value="#{licCert.allLicenseCertMap.entrySet()}"
var="entry" itemValue="#{entry.key}" itemLabel="#{entry.value}" />
</p:selectOneMenu>
</p:column>

Turns out this fixed the problem.
For best practice you should:
move the <h:form> inside the dialog
process the moved <h:form> in the save button.

Related

show and hide primefaces tab via ajax

I have following water down version of primefaces tab view.
<p:tabview>
<p:tab id="1">
<p:selectOneMneu value="#{bean.answer}>
<f:selectItem itemValue="yes"/>
<f:selectItem itemValue="no" />
</p:selectOneMenu>
</p:tab>
<p:tab id="2" rendered=#{bean.answer eq 'yes'} >
<h:outputText="answer is Yes."/>
</p:tab>
<p:tab id="3" rendered=#{bean.answer eq 'no'} >
<h:outputText="answer is No."/>
</p:tab>
</p:tabView>
There is a managed bean which captures the selected value of either "yes" or "no". When the value is evaluated, depends on the answer, one of the tabs will be hidden. Once you are satisfied with the choice made, he/she clicks a submit button to post the data.
My question is what if a user changes his/her mind before pressing a submit button. Go back to drop down menu (selectOneMenu) then changes the value from "yes" to "no". Then I am hoping dynamically the bean would retrieve updated answer without refreshing entire xhtml page. It seems like ajax is the answer but I am not sure how to resolve it.
Here, it works for me. I hope this is what you need. Now you don't have to refresh the page but you have to update the form. I don't know why but updating tabView doesnt effect anything.
<h:form>
<p:tabView>
<p:tab title="select">
<p:selectOneMenu value="#{bean.answer}">
<f:selectItem itemValue="none" itemLabel="select" />
<f:selectItem itemValue="yes" itemLabel="yes" />
<f:selectItem itemValue="no" itemLabel="no" />
<f:ajax event="change" render="#form"/>
</p:selectOneMenu>
</p:tab>
<p:tab title="yes" rendered="#{bean.answer.equals('yes')}">
<h:outputText value="answer is Yes." />
</p:tab>
<p:tab title="no" rendered="#{bean.answer.equals('no')}">
<h:outputText value="answer is No." />
</p:tab>
</p:tabView>
</h:form>

<p:commandButton> won't submit form on first click if <p:inputText> field uses <p:ajax>

I'm having an issue with the following form:
<h:form>
<p:outputPanel autoUpdate="true">
<p:panelGrid columns="2">
<f:facet name="header">
<h:outputText value="Edit a Recycler"/>
</f:facet>
<p:outputLabel value="Recycler Name" for="recyclerName"/>
<p:inputText id="recyclerName" value="#{RecyclerAdmin.editItem.company.companyName}" required="true" requiredMessage="You must name the recycler.">
<p:ajax async="true" />
</p:inputText>
<p:outputLabel value="Zip Code" for="zipCode"/>
<p:inputText id="zipCode" value="#{RecyclerAdmin.editItem.company.primaryAddressId.zip}" required="false">
<p:ajax event="blur" async="true" update="citystate" listener="#{RecyclerAdmin.zipCodeChanged}"/>
</p:inputText>
<p:outputLabel value="City/State"/>
<c:choose>
<c:when test="${RecyclerAdmin.editItem.company.primaryAddressId.city != null and RecyclerAdmin.editItem.company.primaryAddressId.city.length() > 0}">
<h:outputText id="citystate" value="#{RecyclerAdmin.editItem.company.primaryAddressId.city}, #{RecyclerAdmin.editItem.company.primaryAddressId.state}"/>
</c:when>
<c:otherwise>
<p:spacer id="citystate"/>
</c:otherwise>
</c:choose>
<f:facet name="footer">
<p:commandButton id="updatebutton" action="#{RecyclerAdmin.update()}" value="Save" ajax="false"/>
<p:commandButton id="cancelbutton" action="#{RecyclerAdmin.cancel}" value="Cancel" ajax="false" immediate="true"/>
</f:facet>
</p:panelGrid>
</p:outputPanel>
</h:form>
If I make a change to the "Recycler Name" text field, and then immediately click on the save button, the button click highlighting activates, and remains active, but the form does not submit until the button is clicked a second time. If I click somewhere else before clicking on the save button, everything works, and if I remove the ajax async="true" from the recyclerName field, the form also will submit normally, but I need the ajax reference otherwise any changed values in the field are erased when the zipCode field is manipulated.
Any ideas?
The problem was caused by the outputPanel autoUpdate="true" tag. i have added specific update field references to the individual ajax tags and the problem is now gone.
try different event
try removing async=true
p:ajax event="keyup"
http://www.primefaces.org/showcase/ui/ajax/event.xhtml

All dialogs update the backing bean

I have 2 dialogs on a xhtml page:
<p:dialog width="400" id="dialog1" header="Download" widgetVar="dialog1">
<h:outputText value="Field1"/>
<h:inputText value="#{backingBean.field1}"/>
<br/>
<h:outputText value="Field2"/>
<h:inputText value="#{backingBean.field2}"/>
<br/>
<p:commandButton value="Download" ajax="false" onsuccess="PF('diaglog1').hide();">
<p:fileDownload value="#{backingBean.file}"/>
</p:commandButton>
</p:dialog>
<p:dialog width="400" id="dialog2" header="Send" widgetVar="dialog2">
<h:outputText value="Field1"/>
<p:inputText value="#{backingBean.field1}"/>
<br/>
<h:outputText value="Field2"/>
<h:inputText value="#{backingBean.field2}">
<p:ajax update="somePanel"/>
</h:inputText>
<br/>
<h:outputText value="Recipient"/>
<h:panelGroup id="somePanel">
<p:selectOneMenu style="width: 100%;" var="recipient">
<f:selectItems value="#{backingBean.someList}"/>
</p:selectOneMenu>
</h:panelGroup>
<br/>
<p:commandButton value="Send" actionListener="#{backingBean.sendSomething}" onsuccess="PF('dialog2').hide();">
<f:attribute name="item" value="#{recipient}"/>
</p:commandButton>
</p:dialog>
They have different functionality but are on the same page and using the same backing bean. Only one dialog can appear at a time. The problem is when I input some value into the first dialog and press 'Download', it will update the field1 and field2 of the backing bean to the value that I want, but after that the second dialog also updates it to its value, which causes the first one to download the wrong file. If I remove the second dialog, the first will behave correctly.
How do I stop the second dialog from updating the values?
I guess you are keeping both dialogs in one single h:form component.
Then obviously submit in one dialog will submit fields in both dialogs coz, they are in same form.
Don't keep p:dialog inside a h:form, instead use h:form inside
dialog.
You can use multiple h:form s in a page there is no harm in
that, but should not use one h:form in another.
Decide how many forms you can use, based on your design and functionality, In your case you can use 2 h:forms each one inside both dialogs.

p:dialog gets closed on validation error of a submit with ajax="false", how to keep dialog open?

I have the following <p:dialog>
<p:dialog id="dlgDownload" header="#{appmsg['header.download.popup']}" widgetVar="downloadDlg" resizable="true" modal="true" closable="true" width="640" dynamic="false">
<h:form id="frmDownload">
<ui:include src="downloadDialog.xhtml" />
</h:form>
</p:dialog>
The include file contains the following download button:
<p:commandButton id="btnDlgDownload" value="#{appmsg['action.download.label']}" title="#{appmsg['action.download.label']}"
icon="ui-icon-arrowthickstop-1-s" ajax="false" oncomplete="if (!args.validationFailed){downloadDlg.hide();} else {downloadDlg.show();}" process="#this" update=":#{p:component('pnlDownload')}" >
<p:fileDownload value="#{downloadController.downloadFile()}" />
</p:commandButton>
This uses <p:fileDownload> for downloading the file, this means I have to use ajax="false" for <p:fileDownload> to trigger.
But if there is a validation failure in the dialog, then I see that the dialog window gets closed. I want the error message to be shown in the dialog window and not in the main page.
How do I keep the dialog open, so that I can show the error message in the dialog window?
#Balusc Please find my attempt on SSCCE
Basically there is a parent.xhtml where the download button resides and there is a downloadDialog.xhtml embedded on the p:dialog
<p:messages id="globalMessages" globalOnly="true" showDetail="true"
showSummary="true" closable="true" />
<h:form = "parentForm" >
<p:commandButton id="btnDownload"
value="Download"
title="Download"
icon="ui-icon-arrowthickstop-1-s" onclick="downloadDlg.show();">
</p:commandButton>
</h:form>
<p:dialog id="dlgDownload" header="Download" widgetVar="downloadDlg" resizable="true"
modal="true" closable="true" width="640" dynamic="false" visible="#{frmDownload.submitted and facesContext.validationFailed}">
<h:form id="frmDownload" binding="#{frmDownload}">
<ui:include src="downloadDialog.xhtml" />
</h:form>
</p:dialog>
Inside downloadDialog.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsp/jstl/core"
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"
xmlns:pe="http://primefaces.org/ui/extensions">
<p:outputPanel id="pnlDownload">
<h:panelGrid id="dateDisplayGrid" columns="4" style="margin-bottom:10px" cellpadding="5" rendered="#{downloadForm.displayDates}">
<p:calendar id="strtdt" readonlyInput="true" size="12" value="#{downloadForm.startDate}" >
</p:calendar>
<h:outputText value="#{appmsg['label.to']}" />
<p:calendar id="enddt" readonlyInput="true" size="12" value="#{downloadForm.endDate}"
pattern="#{dateFormatting.shortDateFormat}" navigator="true" >
<f:validator validatorId="dateRangeValidator" />
<f:attribute name="startDate" value=":#{p:component('strtdt')}" />
</p:calendar>
<p:message id="dateError" for="enddt" showDetail="true" showSummary="false"></p:message>
</h:panelGrid>
<p:commandButton id="btnDlgDownload" value="Download" title="Download"
icon="ui-icon-arrowthickstop-1-s" ajax="false" oncomplete="if(!args.validationFailed)downloadDlg.hide();" >
<p:fileDownload value="#{downloadController.downloadFile()}" />
</p:commandButton>
<p:button id="btnDlgCancel" value="#{webmsg['action.cancel']}" onclick="downloadDlg.hide(); return false" href="#" />
</p:panel>
</p:outputPanel>
</ui:composition>
When I hit the download button on the dialog window, the error gets displayed on the parent html and dialog remains closed. But when I hit the download button on parent page the dialog window reappears and contains the error message in the inside dialog window.
Thanks for any help.
What if you delegate part of the downloadFile method to another method?
In this case, you would need another method (let's call it prepareDownloadFile) that would be called using ajax. Once this method is complete you can check for errors. In case everything goes well you can call a remoteCommand (with ajax=false) to send the file to the user.
Another idea would be to use iframes. Check out this post.
Hope that helps!

How to skip validation on certain fields in JSF 2 when required

I have two p:dialog. Each one contains some input fields which are marked as required. Only one dialog is shown at a time but when I submit on any of the dialog, JSF also validates the input fields of the dialog which is not shown. What is the best approach to skip the validations in JSF 2 for the dialog which is not shown. One approach could be that I set the required="condation". But dont know what that condition could be and is it goin to work.
Each dialog is initially hidden. Each one has its own button to show. When one is active and I click the save button there is a validation error even when the required field has values. The validation error comes from the inactive dialog panel. May be it give some idea what i am trying to do.
UPDATE
<p:dialog header="Edit Group" widgetVar="dialog_groupEdit" resizable="false"
width="300" showEffect="bounce" hideEffect="explode" modal="true" position="center">
<h:panelGrid id="panel_groupEdit" columns="2">
<h:outputText value="Group Name: "/>
<h:inputText id="input_gnameEdit" size="26" value="#{groupBean.selectionGroup.gname}" required="true" requiredMessage="Edit Group: Name is required."/>
<h:outputText value="Description:"/>
<h:inputTextarea rows="6" cols="23" value="#{groupBean.selectionGroup.description}"/>
<div></div>
<p:commandButton value="Save" action="#{groupBean.saveGroupChanges}" oncomplete="#{args.validationFailed ? '':'dialog_groupEdit.hide()'}"
update="panel_groups panel_groupEdit" style="float:right;"/>
<div></div>
<p:message for="input_gnameEdit"/>
</h:panelGrid>
</p:dialog>
<p:dialog header="New Group" widgetVar="dialog_groupCreate" resizable="false"
width="300" showEffect="bounce" hideEffect="explode" modal="true" position="center">
<h:panelGrid id="panel_groupCreate" columns="2">
<h:outputText value="Group Name: "/>
<h:inputText id="input_gnameCreate" size="26" value="#{groupBean.createGroup.gname}" required="true" requiredMessage="New Group: Name is reqired."/>
<h:outputText value="Description:"/>
<h:inputTextarea rows="6" cols="23" value="#{groupBean.createGroup.description}"/>
<div></div>
<p:commandButton value="Save" actionListener="#{groupBean.saveGroupCreate}" oncomplete="#{empty groupBean.createGroup.gname ? ' ':'dialog_groupCreate.hide()'}"
update="panel_groupCreate panel_groups" style="float:right;"/>
<div></div>
<p:message for="input_gnameCreate"/>
</h:panelGrid>
</p:dialog>
One approach could be that I set the required="condation".
This is going to be clumsy. Just put each individual form in its own separate <h:form> component, or use the process attribute of the <p:commandButton> to identify the region you'd like to process.
<p:commandButton process="panel_groupEdit" ... />
...
<p:commandButton process="panel_groupCreate" ... />
Having a "God" form is in any way a poor practice.
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?
When you are using <p:dialog some of the good practices as advised on the PF forum are -
Never put your <p:dialog inside any other component. Place it somewhere so that it falls right under the <h:body.
Give every <p:dialog it's own form. But, don't place the dialog inside the form, place the form inside the dialog. It's not good to update the dialog itself, only it's content. (I think this should solve your issue also.)
e.g.
<p:dialog widgetVar="dlg" ...
<h:form ...
<h:panelGroup id="dlgContent" ...

Resources