Why does p:resetInput require properties of a managed bean to be set to null first after the form is submitted? - jsf

In a view scoped managed bean, I'm using <p:resetInput> to clear the values held by the properties in the corresponding manged bean like,
<p:commandButton value="Reset" update="panel" process="#this">
<p:resetInput target="panel" />
</p:commandButton>
This works fine.
I have a submit button <p:commandButton> which when pressed causes the submitted values to be inserted into the database, if validation succeeds.
<p:remoteCommand name="updateTable" update="dataTable"/>
<p:panel id="panel" header="New">
<p:outputLabel for="property1" value="property1"/>
<p:inputText id="property1" value="#{bean.property1}" required="true">
<f:validateLength minimum="2" maximum="100"/>
</p:inputText>
<p:message for="property1" showSummary="false"/>
<p:commandButton id="btnSubmit"
update="panel messages"
oncomplete="if(!args.validationFailed) {updateTable();}"
actionListener="#{bean.insert}"
value="Save"/>
<p:commandButton value="Reset" update="panel" process="#this">
<p:resetInput target="panel" />
</p:commandButton>
</p:panel>
The command button invokes the insert() method in the managed bean which is defined as follows.
public void insert() {
if (service.insert(property1)) {
//...Popup a success message.
reset(); //Invoke the following private method.
} else {
//...Show the cause of the failure.
}
}
private void reset() {
property1 = null; //Set this property of type String to null.
}
If this reset() method is omitted, then <p:inputText> will not be cleared as obvious but then if I press the reset button as shown in XHTML, <p:inputText> should be cleared but it doesn't.
The showcase example demonstrates exactly the same thing. Therefore, this behaviour appears to be documented but I don't understand why doesn't <p:resetInut> clear the value of property1, if the reset() method is omitted, in this case?

The <p:resetInput> does not clear the model values as you incorrectly seemed to expect. It just clears the input component's state which may be dirty after a validation error.
The concrete problem it is trying to solve is in detail described in this answer: How can I populate a text field using PrimeFaces AJAX after validation errors occur?
This is the best understood by the following use case:
You have a single view with a single datatable and a single dialog which displays the currently selected record for editing.
You open the dialog and submits its form with invalid values. The input components are marked invalid and highlighted red.
You close the dialog without fixing the errors.
Then you select same or another row for editing. The dialog shows up, but the input components are still marked invalid and highlighted red and show the old submitted value -if any- because it's still the same view state you're working with.
Putting <p:resetInput> with target on dialog's form in the "open dialog" button fixes it.
I'm not sure if your particular case is the right use case for which <p:resetInput> is the right solution. Your code is not complete and you didn't state the concrete functional requirement behind this code anywhere, but as far as I see, there are no multiple inputs/forms which need to update each other. I believe that your case would still work even if you remove <p:resetInput>. So it would be totally superflous in your context and you could just get away with clearing the model (or.. just with refreshing the page by a synchronous GET button which implicitly recreates the view).
See also:
PrimeFaces CommandButton that Doesn't Process Data
Escape a primefaces/jsf page that has required fields

Related

p:dialog form submit loses action method after RequestContext update

I have a small form inside my p:dialog:
<p:dialog id="commentDialog" header="#{managedBean.dialogHeader}" widgetVar="commentDialog" modal="true" resizable="true" height="auto">
<h:form>
<h:outputLabel for="comment" value="Comment:"/>
<p:inputTextarea id="comment" title="Comment"
rows="6" cols="33"
value="#{managedBean.comment}"
required="true"/>
<h:commandButton value="Submit" action="#{managedBean.dialogFormSubmit}"/>
</h:form>
</p:dialog>
Can you tell why, when I hit the Submit button, the dialog does get closed but the dialogFormSubmit() in the managed bean does not get invoked?
I also tried changing to p:commandButton thinking the functionality required the PrimeFaces variant of the h:commandButton but got the same.
The question is similar to this and I tried to do the same but couldn't make it work and also this one which doesn't really seem to have a workable answer.
UPDATE:
The dialog was being shown from the managed bean but was also updated (the solution for which I got here) prior to showing by using the RequestContext API in order to refresh the header:
RequestContext context = RequestContext.getCurrentInstance();
context.update("commentDialog");
context.execute("PF('commentDialog').show();");
I have come to realize that this malfunction occurs only when I update the dialog (middle line above). When I actually don't (which is not critical for the dialog functionality but the header appears blank), the submit action works fine. So the context update seems to be what's messing it up and I don't know how to get both the update while retaining the submit functionality. Could it be a bug in RequestContext.update()?

How to reset input components on change of <p:selectOneMenu> after certain validations are violated

I'm populating <p:selectOneMenu> from a database which contains a list of zones, when a JSF page loaded.
When a zone in this menu is selected, a set of <p:inputText> is displayed in which a user can insert charge that corresponds to product weight which is to be transferred by a transporter to the selected zone in the menu. This can be shown in the following snap shot.
As can be seen, when non numeric values are entered by a user, validation violations occurs, when the given save button <p:commandButton> is pressed (the numbers displayed on top of each text field correspond to weight).
If a user now change the zone in the menu - the first panel without pressing the reset button, the data corresponds to that newly selected zone is loaded in these text fields only when the reset button is pressed as follows (because of validation violation)..
So, how to load data after previous validation violation, if an item (zone) is changed in the menu?
The change event of <p:selectOneMenu>, in this case should do the function something like which is done by <p:resetInput>.
Hope you will be able to understand what I mean :).
Basically, you need the functionality provided by <p:resetInput> inside <p:ajax> of a <p:selectOneMenu>. This is indeed not possible as <p:resetInput> requires being placed in a component implementing ActionSource such as UICommand components.
Your best bet is to let <p:remoteCommand> take over the <p:ajax> change listener job. Therein you can put a <p:resetInput>.
Imagine that you currently have a:
<h:form>
<p:selectOneMenu id="zone">
<f:selectItems ... />
<p:ajax listener="#{bean.changeZone}" update="data" />
</p:selectOneMenu>
<p:panel id="data">
...
</p:panel>
</h:form>
Then this change should do:
<h:form>
<p:selectOneMenu id="zone" onchange="changeZone()">
<f:selectItems ... />
</p:selectOneMenu>
<p:remoteCommand name="changeZone" process="#this zone" action="#{bean.changeZone}" update="data">
<p:resetInput target="data" />
</p:remoteCommand>
<p:panel id="data">
...
</p:panel>
</h:form>
Don't forget to remove the AjaxBehaviorEvent argument from the listener method. It's useless in this particular case anyway.

How to access POST parameters when validation failed

I need to show the response page depending on some of the input fields. E.g. the tabid inputHidden below:
#{controllerBean.tabId}
...
<h:form id="edit">
<h:inputHidden value="#{controllerBean.tabId}" id="tabid" />
<h:inputText value="#{controllerBean.name}" id="name" />
</h:form>
But when some other input in the same form has validation error (e.g. the "name" inputText). The "controllerBean.tabId" value will not be assigned because JSF returns at validation stage.
I still need the tabId to show the page correctly and having 2 ideas in mind:
#{param['edit:tabid']}
or use binding:
#{tabId.value}
<h:inputHidden value="#{controllerBean.tabId}" id="tabid" binding="tabId" />
My question is, which of these 2 is the better or Best Practice? Or there are even better ways to do this?
update:
Note. In my specific case, the tabid is set by client javascript.
Server reply with a few items in the html.
Javascript put these items into different tabs on the page.
One of the tabs POST data to server with the current tabid in the form.
So my server need to know the tabid to show the response page with the correct tab selected.
You can add a lifecycle event listener to the component and pick the value from it. I'm going to recommend the preValidate listener:
<h:form id="edit">
<h:inputHidden value="#{controllerBean.tabId}" id="tabid">
<f:event type="preValidate" listener="#{controller.grabTabId}"/>
</h:inputHidden>
<h:inputText value="#{controllerBean.name}" id="name" />
</h:form>
This registers the listener to fire just before the validation phase of the request. You'll now have a listener defined in your backing bean to look like:
public void grabTabId(ComponentSystemEvent cse){
//obtain a reference to the component
HtmlInputHidden hiddenElement = (HtmlInputHidden)cse.getComponent();
//get the value from the component.
String hiddenValue = hiddenElement.getValue();
}
<h:form id="edit">
<h:inputHidden value="#{controllerBean.tabId}" id="tabid" />
<h:inputText value="#{controllerBean.name}" id="name" >
<p:ajax process="tabid" immediate="true" event="keyup" />
</h:inputText>
</h:form>
The above code will do is when the user put some value the value will be processed and will be set the managedBean. that what you want I think.
Another non-perfect way of accomplishing this is to move the validation logic to your action method. If validation fails, you just stop processing (and add an applicable FacesMessage). You just need to be aware that all model values will have been updated, and you can clear them if necessary.
Since updating model values on failed validation goes against the JSF lifecycle, I think any solution will be somewhat of a hack.

<p:commandButton CONDITIONAL onclick event

i have a jsf-form with an input field and a save-button as seen in the code below. What i want to achieve is, when the save-button clicked, the input should be validated with the regex-pattern. If the validation failed, no save-confirmation-dialog should be shown. Otherwise a save-confirmation-dialog shown, and let the user to choose if to save or not.
In the code below, the dialog has always been shown, despite the conditional onclick="if(#{conditionOK}). I want no confirmation-dialog got shown, when conditionOK returns false!!! After many tries, i think the facescontext.isValidateFailed() will not be re-evalutated.
Please help :(
All what i want, is only to check, if the regex-Validator returns true. For this case, the confirmation-dialog should be shown.
My approach could be wrong. Many thank if you guys have also other solutions.
<h:form id="save_all_form">
<p:inputTextarea rows="1" style="width:100%;resize:none"
value="#{cusBean.saveAll}" autoResize="false"
validatorMessage="Wrong format">
<f:validateRegex pattern="#{msgs.pattern}" />
</p:inputTextarea>
<ui:param name="conditionOK"
value="#{facesContext.postback and !facesContext.validationFailed}" />
<p:commandButton value="#{msgs.button_overwrite_all}"
onclick="if(#{conditionOK}){confirmation.show()}"/>
</h:form>
I do not think that the JSF-validation is the way to go for you. It is intended to prevent the change of model data in the case, that the validation fails.
And if you would like to make a check in JavaScript you have to update the section in HTML. JavaScript does not reevaluate the Expression, so the value when the view was rendered the first time will be used everytime.
Try the following in the xhtml:
<h:form id="save_all_form">
<p:inputTextarea id="input" rows="1" style="width:100%;resize:none"
value="#{cusBean.saveAll}" autoResize="false">
<p:ajax global="false" update="input submit" partialSubmit="true"/>
</p:inputTextarea>
<p:commandButton id="submit" value="#{msgs.button_overwrite_all}"
onclick="if(#{cusBean.validate(msgs.pattern)}){confirmation.show()}"/>
</h:form>
And add this method in CusBean:
public boolean validate(String pattern) {
return getSaveAll().matches(pattern);
}
The result will be, that there is not JSF validation which takes place and the value of the textArea is submitted everytime you change it. Plus the commandButton-section is updated so the condition will be updated.
Like the other answer explained onclick event is too early to check the validation status of a JSF request(using !facesContext.validationFailed) because the request has not been submitted yet; Validation has not been run so the validation status will always be false (well, sort of) during onclick.
So what you'll want to do is carry out an ajax validation of the field (like shown in the earlier answer) and then use the primefaces args variable to check the status of the request:
<p:commandButton value="#{msgs.button_overwrite_all}" id="createReport" onclick="if(!args.validationFailed){confirmation.show();}"/>

PrimeFaces autocomplete: itemSelect versus change events

I need to trigger an ajax update upon change to a text box, which is a <p:autoComplete> component. I have observed that if the user opts to type the text manually, the event is a change, whereas if the user clicks one of the suggestions for the autocomplete, the event is itemSelect. So I added two <p:ajax> children to the input, each calling the same method and having the same update list, but one having event="change" and the other event="itemSelect".
However, I now discover something odd. For example, while in normal server mode I opened my page and typed "12". The autocomplete offered "1233" and "1234" as suggestions. I clicked "1233" and seemingly nothing happened. I clicked again and everything else filled in.
Repeat this in the debugger with a breakpoint on the event handler, and I can see that after the first click, the value is "12" and on the second click, it becomes "1233".
By switching commenting out the two different <p:ajax> I can see the different consequences. Without the "change" one, the handler is never called if the user selects an autocomplete suggestion, and without the "itemSelect" one, the handler is never called if the user types manually. But with both of them, there are two calls, and I'm sure there will be complaints about the double-click.
Some pseudo-code for those that like, first the xhtml:
<p:autoComplete id="itemId" value="#{myBacker.myBean.itemNumber}"
required="true" completeMethod="#{myBacker.idAutoComplete}">
<p:ajax event="itemSelect" update="beanDetails"
listener="#{myBacker.idChangeEventListener()}" />
<p:ajax event="change" update="beanDetails"
listener="#{myBacker.idChangeEventListener()}" />
</p:autoComplete>
<h:panelGroup id="beanDetails">
<h:panelGroup rendered="#{not empty myBacker.myBean.institutionName}">
<h:outputText value="#{myBacker.myBean.institutionName}" />
<!-- Continues with address, phone, etc.. -->
</h:panelGroup>
</h:panelGroup>
Then the Java backing bean code:
public void idChangeEventListener() {
myBean = myDAO.getDetails(myBean);
// another couple of init-type method calls
}
Give the parent tag a widgetVar attribute, then add this little attribute to the <p:ajax event="change" ...> child tag:
onstart="if(widgetVarName.panel.is(':visible')) return false;"
When the question was written, we were on PrimeFaces version 3.5, if I recall correctly. Since then, we need to update the solution to:
onstart="if(PF('widgetVarName').panel.is(':visible')) return false;"
with thanks to mwalter for pointing out the change.

Resources