I have a form with multiple fields, of which I need one of them required to continue or a group of them. For simplicity, I'll just paste a simpler version of my code here
<h:form id="searchForm">
<p:growl for="searchForm" showDetail="true" showSummary="true"/>
<p:inputText id="name"
value="#{backingBean.name}"
required="#{backingBean.nameRequired and backingBean.masterRequired}">
<p:ajax />
</p:inputText>
<h:panelGroup id="dateForm">
<p:inputMask id="date"
value="#{backingBean.date}"
mask="99/99/9999"
required="#{backingBean.dateRequired and backingBean.masterRequired}"
converterMessage="Please insert using format dd/mm/yyyy">
<f:convertDateTime pattern="dd/MM/yyyy" />
<f:validator validatorId="dateValidator" />
<p:ajax update="dateForm" />
</p:inputMask>
</h:panelGroup>
<p:selectOneMenu id="documentType" effect="fade"
value="#{backingBean.documentType}"
required="#{backingBean.documentRequired and backingBean.masterRequired}">
<f:selectItem itemLabel="Select document type" noSelectOption="true" />
<f:selectItems
value="#{constantsController.docType.entrySet()}"
var="entry" itemValue="#{entry.key}" itemLabel="#{entry.value}" />
<p:ajax />
</p:selectOneMenu>
<p:inputText id="documentNumber"
value="#{backingBean.documentNumber}"
required="#{backingBean.documentRequired and backingBean.masterRequired}">
<p:ajax />
</p:inputText>
<p:commandButton id="searchButton"
value="Search"
action="#{controllerBean.submitSearch}"
icon="ui-icon-search">
<p:ajax
listener="#{backingBean.checkRequired()}" update="#form" />
</p:commandButton>
</h:form>
When all fields are empty, the is shown as it should. Now what I need is the inputMask date to only show the converter message and the validation message. I need it to not show the message when the requiredMessage will try to be shown.
I tried putting a <p:message for="date" rendered="#{!empty param['date']}" /> but it does not work, since it is not rendered on the first load, and ajax does not update the panelGroup, I think it is because since I gave an invalid value to the converter, it does not fire the update.
Additional information:
As you can see, I have multiple required fields, I need at least one of these:
-name
-date
-document type + document number
Now, to validate the required fields, I'm doing the following on my backing bean:
public void checkRequired() {
nameRequired = name.equals("");
dateRequired = date == null;
documentRequired = documentType.equals("") || documentNumber.equals("");
masterRequired = nameRequired && dateRequired && documentRequired;
if(masterRequired)
{
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Incomplete form",
"Please insert at least 1 field");
FacesContext.getCurrentInstance().addMessage("searchForm", message);
return;
}
}
Related
<h:form id="newStudentForm">
<h:outputLabel value="Student" for="studentId" />
<p:selectOneMenu value="#{myBean.studentId}" id="studentId">
<f:selectItems value="#{myBean.studentList}" var="student"
itemLabel="#{student.name}" itemValue="#{student.id}" />
</p:selectOneMenu>
<h:outputLabel value="Address" for="addressId" />
<p:selectOneMenu value="#{myBean.addressId}" id="addressId">
<f:selectItems value="#{myBean.addressList}" var="address"
itemLabel="#{address.name}" itemValue="#{address.id}" />
</p:selectOneMenu>
<h:outputLabel value="Address" for="addressId" />
<p:selectOneMenu value="#{myBean.subjectId}" id="subjectId">
<f:selectItems value="#{myBean.subjectList}" var="subject"
itemLabel="#{subject.name}" itemValue="#{subject.id}" />
<a4j:ajax event="valueChange"
render="newStudentForm"
listener="#{myBean.checkSubject}"
execute="#this"/>
</p:selectOneMenu>
<h:outputLabel value="Price" for="priceId" rendered="#{myBean.checkSubject}" />
<p:selectOneMenu value="#{myBean.priceId}" id="priceId"
rendered="#{myBean.checkSubject}">
<f:selectItem itemValue="#{null}" itemLabel="" />
<f:selectItems value="#{myBean.priceList}" var="price"
itemLabel="#{price.name}" itemValue="#{price.id}"/>
</p:selectOneMenu>
</h:form>
I am trying to make a field dynamic i.e field Price, when i am selecting a value from subject, the price field is dependent on that value. Everything is working fine in this code except that when i am rendering the form, the values that i enter in other fields(like address) before selecting subject is being overridden by the initial values. So how should i refactor this ajax event call so that the values do not get overridden.
The checkSubject function is returning true or false based on subject selected.
I am relatively new to JSF and Primefaces. I have a page in which I have three selectOneMenu displaying the same set of values from a map. I would like to make sure that the user selects different values for the three drop downs. I have achieved this by writing a custom validator. But the validator works only if I click the submit page. I want to have an ajax call which would show an error message for drop down 2 as soon as the user selects the same value as drop down 1.Also the same case for drop down 3.Here is my code snippet:
user.xhtml
<h:outputLabel for="Question1" value="#{msg['account.question1']}"/>
<h:message styleClass="validation-error" for="Question1"/>
<h:selectOneMenu id="Question1" required="true" value="#{account.question1}" class="smallTxt">
<f:selectItems value="#{controller.questionMap}" />
<f:validator validatorId="com.validator.QuestionsValidator"></f:validator>
</h:selectOneMenu>
<h:outputLabel for="Answer1" value="#{msg['account.answer1']}"/>
<h:message styleClass="validation-error" for="Answer1"/>
<h:inputText id="Answer1" required="true" value="#{account.answer1}" />
<h:outputLabel for="Question2" value="#{msg['account.question2']}"/>
<h:message styleClass="validation-error" for="Question2"/>
<h:selectOneMenu id="Question2" required="true" value="#{account.question2}" class="smallTxt">
<f:selectItems value="#{controller.questionMap}" />
</h:selectOneMenu>
<h:outputLabel for="Answer2" value="#{msg['account.answer2']}"/>
<h:message styleClass="validation-error" for="Answer2"/>
<h:inputText id="Answer2" required="true" value="#{account.answer2}" />
<h:outputLabel for="Question3" value="#{msg['account.question3']}"/>
<h:message styleClass="validation-error" for="Question3"/>
<h:selectOneMenu id="Question3" required="true" value="#{account.question3}" class="smallTxt">
<f:selectItems value="#{controller.questionMap}" />
</h:selectOneMenu>
<h:outputLabel for="Answer3" value="#{msg['account.answer3']}"/>
<h:message styleClass="validation-error" for="Answer3"/>
<h:inputText id="Answer3" required="true" value="#{account.answer3}" />
I am using JSF 2 and Primefaces 5.2.
Thanks in advance
If you want to execute your validator on an AJAX call, you have to add <f:ajax /> to your <h:selectOneMenu>
<h:selectOneMenu id="Question1" required="true" value="#{account.question1}" class="smallTxt">
<f:selectItems value="#{controller.questionMap}" />
<f:validator validatorId="com.validator.QuestionsValidator"></f:validator>
<f:ajax />
</h:selectOneMenu>
Side question: You state, that you use Primefaces 5.2, but you use JSF standard components (<h:selectOneMenu> instead of <p:selectOneMenu>). Is that on purpose?
You can apply listener on selectonemenu.linke this:
<p:selectOneMenu id="country" value="#{dropdownView.country}" style="width:150px">
<p:ajax listener="#{dropdownView.onCountryChange}" update="city" />
<f:selectItem itemLabel="Select Country" itemValue="" noSelectionOption="true" />
<f:selectItems value="#{dropdownView.countries}" />
</p:selectOneMenu>
And then in this oncountrychange() function you will get the values of all the three select items and compare them.
I have implemented a custom validator for my screen referring to the example given here.
But in my case, my validator method is not invoked if I don't enter any values in any of the field. So the check for empty fields is never done. The required messages are displayed everytime.
If I removed the required attributes, even in that case the validator is invoked only if the fields have some value in them. How do I get all my validations to be done in the validator class?
My xhtml:
<h:form>
<p:messages id="message" closable="true"/>
<h:panelGrid columns="3" id="changePassPanel">
<h:outputLabel for="pwd0" value="Current password :" />
<p:password id="pwd0" value="#{homeBean.password1}">
<f:validator validatorId="PasswordValidator"></f:validator>
<f:attribute name="pwd1" value="#{pwd1}" />
<f:attribute name="pwd2" value="#{pwd2}" />
</p:password>
<h:outputLabel for="pwd1" value="New password :" />
<p:password id="pwd1" value="#{homeBean.password2}" binding="#{pwd1}"/>
<h:outputLabel for="pwd2" value="Confirm new password :" />
<p:password id="pwd2" binding="#{pwd2}"/>
</h:panelGrid>
<p:commandButton id="saveButton" value="Save" validateClient="true"/>
</h:form>
I have a CRUD page which shows data from a query (a List of domain objects) in a Primefaces datatable.
<p:dataTable
id="negozi"
var="n"
value="#{nController.theListFromQuery}"
rowKey="#{n.id}"
selection="#{nController.selected}"
selectionMode="single">
<p:column headerText="Field1">
<h:outputText value="#{n.f1}" />
</p:column>
<p:column headerText="Field2">
<h:outputText value="#{n.f2}" />
</p:column>
<p:column style="width:4%">
<p:commandButton
actionListener="#{nController.prepareEdit(n)}"
update=":editDialogId"
oncomplete="editDialog.show()"
value="Edit" />
</p:column>
...
By clicking on the edit button a dialog will be shown:
<p:dialog
header="Edit N"
widgetVar="editDialog"
id="editDialogId">
<h:form id="formDialog">
<h:panelGrid id="editDialogTable" columns="2" cellpadding="10" style="margin:0 auto;">
<p:outputLabel for="field1" value="F1:" />
<p:inputText id="field1" value="#{nController.selected.f1}" />
<p:outputLabel for="field2" value="F2:" />
<p:inputText id="field2" value="#{nController.selected.f2}" />
<p:commandButton
value="Confirm"
actionListener="#{nController.doEdit}"
update=":form"
oncomplete="editDialog.hide()"
rendered="#{nController.selected.id!=null}" />
...
It works. Now I want to make F1 a required field.
I add the "required" attribute to the inputText field and what happens?
When I try to confirm the form without the required field, the entity is not edited (that's right) but the dialog is closed (that's NOT right!)
When I reopen the dialog I can see the red highlight on the required (and invalid) field.
What I want is to prevent the dialog closing if the form is invalid.
Do I have to write some JS or will JSF help me?
The PrimeFaces ajax response puts an args object in the scope which has a validationFailed property. You could just make use of it.
oncomplete="if (args && !args.validationFailed) PF('editDialog').hide()"
(the args precheck is necessary to not cause a JS error when an exception is thrown during request)
You could refactor it to a reusable JS function as follows.
oncomplete="hideDialogOnSuccess(args, 'editDialog')"
function hideDialogOnSuccess(args, dialogWidgetVar) {
if (args && !args.validationFailed) {
PF(dialogWidgetVar).hide();
}
}
this post is now three years old, but I have found helpful, so my findings may help others.
In PF 5.x at least, it seems that the solution provided by BalusC has to be modified in two ways. (1) add the "args" argument to the call in oncomplete event hander, and (2) use the PF primefaces primitive to identify the widget in PF tables. Here is the code I am using:
oncomplete="hideDialogOnSuccess(args, PF('editDialog'))"
function hideDialogOnSuccess(args, dialogWidgetVar) {
if (args && !args.validationFailed) {
dialogWidgetVar.hide();
}
}
I believe this is the cleanest solution.
Doing this you don't need to change your buttons code.
This solution overrides the hide function prototype.
$(document).ready(function() {
PrimeFaces.widget.Dialog.prototype.originalHide = PrimeFaces.widget.Dialog.prototype.hide; // keep a reference to the original hide()
PrimeFaces.widget.Dialog.prototype.hide = function() {
var ajaxResponseArgs = arguments.callee.caller.arguments[2]; // accesses oncomplete arguments
if (ajaxResponseArgs && ajaxResponseArgs.validationFailed) {
return; // on validation error, prevent closing
}
this.originalHide();
};
});
This way, you can keep your code like:
<p:commandButton value="Save" oncomplete="videoDetalheDialogJS.hide();"
actionListener="#{videoBean.saveVideo(video)}" />
to keep the dialog Open on validation Failed, you just need set the commandButton as follows:
<p:commandButton value="save"
action="#{YourBean.yourActionMethod}"
oncomplete="if (!args.validationFailed) PF('yourDialogWidgetVar').hide()"/>
I gonna leave here a complete example:
<h:form id="ad-form">
<p:dialog id="ad-dialog" widgetVar="adDialog" modal="true" width="400"
closeOnEscape="true" resizable="false" header="Addreass">
<p:messages id="a-msgs" closable="true" />
<h:panelGrid columns="2" id="ad-painel-dialog" width="100%">
<p:outputLabel value="Country" for="country" />
<p:inputText id="country" style="width:100%"
value="#{clientSaverBean.editableAddress.country}" />
<p:outputLabel value="City" for="city" />
<p:inputText id="city"
value="#{clientSaverBean.editableAddress.city}" />
<p:outputLabel value="Zip-Code" for="zipcode" />
<p:inputText id="zipcode"
value="#{clientSaverBean.editableAddress.zipCode}" />
<p:outputLabel value="Street" for="street" />
<p:inputTextarea id="street"
value="#{clientSaverBean.editableAddress.street}" />
<p:outputLabel value="Number" for="number" />
<p:inputText id="number"
value="#{clientSaverBean.editableAddress.number}" />
<h:panelGroup />
<f:facet name="footer">
<p:commandButton value="save"
action="#{clientSaverBean.saveAddress}"
process=":ad-form:ad-dialog"
update=":ad-form:a-msgs :ad-form:ad-painel-dialog :client-form:ad-table"
oncomplete="if (!args.validationFailed) PF('adDialog').hide()"/>
</f:facet>
</h:panelGrid>
</p:dialog>
</h:form>
The dropdown:
<h:outputLabel value="#{build.approvedRecons}" for="reconSearchFunctionalAreaID"></h:outputLabel>
<p:selectOneMenu style="width:200px;" id="reconSearchFunctionalAreaID" >
<f:selectItem itemValue="-Select One-" itemLabel="-Select One-" />
<f:selectItems value="#{approvedReconDetailsBean.reconItemList}"/>
<p:ajax update="#form" listener="#{approvedReconDetailsBean.reconDetailsDisplay}" event="onChange"></p:ajax>
</p:selectOneMenu>............<h:outputLabel for="reconNameID" value="#{build.appvReconName}" />
<h:outputText value="#{build.colon}" />
<h:outputText value="#{approvedReconDetailsBean.reconCtxVO.reconID}" id="reconNameID" />
The listener:
public void reconDetailsDisplay(SelectEvent event){
ReconContextVO tempReconContextVO = ((ReconContextVO) event.getObject());
ReconContextVO reconCtxVO1 = new ReconContextVO();
reconCtxVO1.setReconID(tempReconContextVO.getReconID());
reconCtxVO1.setReconName(tempReconContextVO.getReconName());
reconCtxVO1.setTxnProcessingType(tempReconContextVO.getTxnProcessingType());
reconCtxVO1.setTxnProcessingType(tempReconContextVO.getTxnProcessingType());
this.setReconCtxVO(reconCtxVO1);
}
reconItemList is of type List<ReconContextVO>. In my bean I converted reconsList to reconItemList. ReconContextVO contains
private String reconName;
private String txnProcessingType;
private String txnProcessingLevel;
// and their setter & getters
Now I would like to display reconName, txnProcessingType, txnProcessingLevel in text fields on change of the dropdown. I wrote the ajax listner method like above code. I din't get any idea.
Your concrete problem is caused by incorrect usage of <p:ajax>. The event="onChange" is invalid. It should be event="change" (which is the default already and thus can safely be omitted). The listener method argument is also invalid, it should be AjaxBehaviorEvent.
But, after all, you don't need a listener method for this. You can just bind the <p:selectOneMenu value> directly to a bean property.
<p:selectOneMenu value="#{approvedReconDetailsBean.reconCtxVO}">
<f:selectItem itemValue="-Select One-" itemLabel="-Select One-" noSelectionOption="true" />
<f:selectItems value="#{approvedReconDetailsBean.reconItemList}" />
<p:ajax update="reconDetails" />
</p:selectOneMenu>
<h:panelGroup id="reconDetails">
<h:outputText value="#{approvedReconDetailsBean.reconCtxVO.reconID}" />
<h:outputText value="#{approvedReconDetailsBean.reconCtxVO.reconName}" />
<h:outputText value="#{approvedReconDetailsBean.reconCtxVO.txtProcessingType}" />
<h:outputText value="#{approvedReconDetailsBean.reconCtxVO.txnProcessingLevel}" />
</h:panelGroup>
Note that I assume that you've already a Converter for the object and that its equals() is properly implemented. You should get conversion/validation error on that if not properly done.