<p:commandButton CONDITIONAL onclick event - jsf

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();}"/>

Related

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.

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.

CommandLink with input text

I have input text, command link and a logout image in my page. My command link don't work when I use "required" in input text. otherwise it works fine.
Here is my code:
<p:commandLink action="#{loginForm.logout}">
<p:graphicImage value="images/logout.png" alt="Logout" style="width: 50px;height: 50px;" title="Logout"/>
</p:commandLink>
<p:inputText id="fname" required="true"/>
The command links and buttons submit by default the entire form. In this case, the input field is being validated and gave a "This field is required" validation error (which you should have noticed if you had a <p:messages autoUpdate="true"> or have paid more love and attention to server log).
However, your logout command seems to stand entirely at its own and all other inputs in the same form have completely nothing to do with the logout command.
There are several solutions, in the order of recommendation:
Put the logout command in its own form.
<h:form>
<p:commandLink value="Logout" ... />
</h:form>
<h:form>
Other form.
</h:form>
This makes design technically and semantically the most sense.
Tell the logout command to process only itself on submit.
<p:commandLink value="Logout" process="#this" ... />
This defaults namely to #form which means "the entire form". Use this only if a separate form is absolutely not an option for some reason (e.g. due to poor CSS design and/or not being well versed in basic HTML/CSS).
Abuse the immediate attribute.
<p:commandLink value="Logout" immediate="true" ... />
This will bypass all inputs which do not have the immediate attribute. But this would fail when there are actually inputs which do need the immediate attribute to prioritize validation.
This is because the action is blocked during the validation phase. Add immediate="true" to your commandLink and it should work fine.
For more info see here.

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

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

JSF 2 - No way to do Required Inputs + Clear (Immediate) Button?

This question is similar to the question here but that solution doesn't work here.
Take this simple-to-the-max example:
<h:form>
<h:inputText required="true" value="#{mrBean.someValue}" />
<h:inputText required="true" value="#{mrBean.someValue2}" />
<h:commandButton value="Submit">
<f:ajax execute="#form" />
</h:commandButton>
<h:commandButton immediate="true" action="#{mrBean.clearAllValues}" value="Clear">
<f:ajax render="#form" />
</h:commandButton>
</h:form>
And the bean Code:
public void clearAllValues() {
setSomeValue(null);
setSomeValue2(null);
}
Take this scenario:
Enter 'X' value in first input
Submit it using the 'Submit' Button. (failed in validation)
Enter 'Y' into the same input.
Click the 'Clear' button.
Result: Inputs don't clear and value of first input returns to 'X'.
I would expect this scenario to clear the input values but it doesn't, instead, it restores 'X' which is the previously submitted value. It actually never really runs mrBean.getSomeValue() on the bean (Which would have returned null and clear the input field)
The problem is related to JSF not working well with required fields and immediate. I wonder if anyone managed to overcome this problem.
Thanks!
Ben.
Your code example is oversimplified. The described problem symptoms will only occur when you have multiple required inputs. Add one more required input field to the example. Fill out only one of them. A validation error will occur for the empty one. Then enter something else in both and press clear. The valid input will indeed retain the previously submitted value.
This problem is described in detail in this question and this blog article. The solution boils down to collecting all to-be-cleared input components and calling EditableValueHolder#resetValue() on each of them. This can be done with a <f:actionListener> as shown in the blog article.
Another way in your particular case since you just want to clear out the entire form is to use a <h:button> which will basically just refresh the page. If your bean is request or view scoped then it will also be recreated with all properties set to default.
<h:form>
<h:inputText required="true" value="#{mrBean.someValue}" />
<h:commandButton value="Submit">
<f:ajax execute="#form" />
</h:commandButton>
<h:button value="Clear" />
</h:form>
Are you sure clearAllValues is executed? Do you get any errors in the logs or console?
Try adding execute
<f:ajax render="#form" execute="#this">

Resources