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>
Related
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
JSF beans are generally not updated when the validation fails, which in some cases causes really ugly effects, for example, when using facet="output" of p:inplace:
<h:form>
<h:panelGrid id="panel" columns="3" cellpadding="2">
<p:outputLabel value="My Field" for="myfield" />
<p:inputText id="myfield" value="#{test.myField}" required="true" />
<p:message for="myfield" />
<h:outputText value="Checkbox: " />
<p:inplace id="checkboxInplace" effect="none">
<f:facet name="output">#{test.myBooleanText}</f:facet>
<f:facet name="input">
<h:selectBooleanCheckbox value="#{test.myBoolean}" />
</f:facet>
</p:inplace>
<p:spacer />
</h:panelGrid>
<p:commandButton id="refresh" icon="ui-icon-refresh" update="panel" process="#form"/>
</h:form>
The output facet defines the inplace labels, which should be localized instead of standard ones:
private boolean myBoolean;
public String getMyBooleanText() {
return myBoolean ? "Ja" : "Nein";
}
However, when the validation fails, the inplace output facet shows the old value of the checkbox, not the actual one. If you click on it, a real value is shown.
How to solve that issue and actualize the output correctly? Submiting the values to the bean would be the best, because I have no problem with consistent state of values on the client and server, as long no action is actually executed (asserted by the validation).
Haven't tried it myself, but give this a chance:
<p:inplace id="checkboxInplace" effect="none">
<f:facet name="output">#{test.myBoolean ? 'Ja' : 'Nein'}</f:facet>
<f:facet name="input">
<h:selectBooleanCheckbox value="#{test.myBoolean}" immediate="true">
<p:ajax update="#parent" />
<h:selectBooleanCheckbox />
</f:facet>
</p:inplace>
I want to have a form with JSF (Primefaces) to have a required field (the username is this example) to be required when saved. Also you can add books to every user, a user can have 0 ... n books. If you add a new book, it is required to give it an author and a name.
I tried it with the code below and already tried many ways of the Partial Processing of Primefaces. However, it is not working correctly. Sometimes I have to enter the required username to add a book or save it not working at all. Is there a way, to only check the required username on save and ignore the required author and bookname?
This is the code for the example:
<h:form>
<p:outputPanel id=„userdetails“>
<p:inputText id="name" value="#{bean.name}" />
</p:outputPanel>
<p:inputText id="txt_title" value="#{createBookBean.book.title}"
required="true" />
<p:inputText id="txt_author" required="true"
value="#{createBookBean.book.author}" />
<p:commandButton value="Reset" type="reset" />
<p:commandButton id="btn_add" value="Add"
update="books msgs #parent" action="#{createBookBean.reinit}">
<p:collector value="#{createBookBean.book}"
addTo="#{createBookBean.books}" />
</p:commandButton>
<p:outputPanel id="books">
<p:dataTable id="booksTable" value="#{createBookBean.books}"
var="book">
<h:outputText value="#{book.title}" />
<h:outputText value="#{book.author}" />
<p:column>
<p:commandLink value="Remove" update=":form:books"
process=":form:books">
<p:collector value="#{book}"
removeFrom="#{createBookBean.books}" />
</p:commandLink>
</p:column>
</p:dataTable>
</p:outputPanel>
<p:commandButton value="Save" update="msgs" process="#form"
action="#{bean.save()}"></p:commandButton> // button to save, and ignore required bookname
</h:form>
// button to save, and ignore required bookname
For that purpose you can use immediate attribute of commandButton:
<p:commandButton value="Save" update="msgs" process="#form"
action="#{bean.save()}" immediate="true" />
I have the following JSF code in my page
<h:panelGroup id="rSelectionPanel" rendered="#{bean.admin}">
<h4 class="header-line">Admin Panel</h4>
<h:panelGroup rendered="#{bean.selectionMode=='RS'}">
<h:form styleClass="registerForm">
<h:outputLabel value="End Line1?" rendered="#{not bean.endLine2}"></h:outputLabel>
<h:selectBooleanCheckbox id="endLine1" value="#{bean.endLine1}" rendered="#{not bean.endLine2}">
<p:ajax event="change" update=":rSelectionPanel"></p:ajax>
</h:selectBooleanCheckbox>
<h:outputLabel value="End Line2?" rendered="#{not bean.endLine1}"/>
<h:selectBooleanCheckbox id="endLine2" value="#{bean.endLine2}" rendered="#{not bean.endLine1}">
<p:ajax event="change" update=":rSelectionPanel"></p:ajax>
</h:selectBooleanCheckbox>
<h:inputTextarea id="newLine2Name" styleClass="form-poshytip" title="Line2 Name" rows="1" maxlength="50"
value="#{bean.newLine2Name}" validatorMessage="Too many characters" rendered="#{bean.endLine2}">
<f:passThroughAttribute name="placeholder" value="Line2 Name" />
<f:validateLength maximum="50" />
</h:inputTextarea>
<h:commandButton styleClass="submit" value="Select Line" action="#{bean.confirmLineBy}">
</h:commandButton>
</h:form>
</h:panelGroup>
</h:panelGroup>
With the following backing bean java code
public void confirmLineBy(){
getLog().debug("Entering confirmLineBy....");
ConfirmLineByRequest request = new ConfirmLineByRequest();
request.setPage(getPage());
request.setEndLine1(endLine1);
if(isEndLine2())request.setNewLine2Name(newLine2Name);
request.setEndLine2(isEndLine2());
ConfirmLineByResponse response = LineService.confirmLineBy(request, null);
nextUnconfirmedLines.removeAll(nextUnconfirmedLines);
setConfirmedLines(response.getConfirmedLines());
setLine2s();
setAddedLine(false);
getLog().debug("CONFIRMED LINES SIZE: "+confirmedLines.size());
getLog().debug("Exiting confirmLineBy....");
}
When clicking the commandButton with neither of the boxes checked, it submits fine. But when checking either of the checkboxes, it doesn't even call bean.confirmLineBy().
Any ideas?
Changed from using to . sorted now.
I am trying to update a selectOneMenu from the results of another selectOneMenu.
When group is selected the user menu should be updated.
I have verified that the data for the user menu is being updated. It is not being rendered however.
Currently running Primefaces 3.4.2 and JSF 2.1
<ui:composition>
<br/><br/>
<h:form id="transferForm">
<h:panelGrid columns="1" style="width: 500px;margin: auto;text-align: center" >
<h:panelGroup>
<h:outputLabel for="group" value="Group" />
<h:selectOneMenu id="group" value="#{projectBean.transferUtil.selectedTransferGroup}" >
<f:selectItems value="#{projectBean.transferUtil.transferGroups}" />
<f:ajax execute="group" render="user" />
</h:selectOneMenu>
<br />
<h:outputLabel for="user" value="User" />
<h:selectOneMenu id="user" value="#{projectBean.transferUtil.selectedTransferUser}" required="true" requiredMessage="Select User" >
<f:selectItems value="#{projectBean.transferUtil.transferUsers}" />
</h:selectOneMenu>
</h:panelGroup>
<p:commandButton id="projectTransferButton" action="#{projectBean.transferUtil.transfer}" value="Transfer" update=":projtabs,:growlForm:growlMesg">
<f:setPropertyActionListener target="#{projectBean.activeTab}" value="#{projectBean.project_tab_index}" />
</p:commandButton>
</h:panelGrid>
</h:form>
<br/><br/>
[EDIT]
Alright this is the error I am getting.
<?xml version='1.0' encoding='UTF-8'?>
<partial-response><error><error-name>class java.lang.IllegalArgumentException</error-name><error-message><![CDATA[rss02.1 OPERA]]></error-message></error></partial-response>
And this is the code in question.
<p:dataGrid var="area" value="#{projectBean.projectUtil.project.rssAreas}" columns="1">
<p:column>
<h:selectBooleanCheckbox id="rss#{area.shortName}" label="#{area.name}" value="#{area.active}" />
<h:outputText value="#{area.name}" />
</p:column>
</p:dataGrid>
You should not perform business logic in getters/setters. They are invoked multiple times in JSF lifecycle and are intented to get and set the property. You should perform business logic in action(listener) methods instead.
The following construct should work:
<h:selectOneMenu id="group" value="#{projectBean.transferUtil.selectedTransferGroup}" >
<f:selectItems value="#{projectBean.transferUtil.transferGroups}" />
<f:ajax execute="group" listener="#{projectBean.transferGroupChanged}" render="user" />
</h:selectOneMenu>
<h:selectOneMenu id="user" value="#{projectBean.transferUtil.selectedTransferUser}" required="true" requiredMessage="Select User" >
<f:selectItems value="#{projectBean.transferUtil.transferUsers}" />
</h:selectOneMenu>
With
public void transferGroupChanged(AjaxBehaviorEvent event) {
// Change the transferUsers here.
}
The getters and setters should not contain any business logic. They should merely get and set the property.
See also:
Why JSF calls getters multiple times
How to load and display dependent h:selectOneMenu on change of a h:selectOneMenu