PrimeFaces autocomplete: itemSelect versus change events - jsf

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.

Related

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.

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

ui:repeat with a list sending right object to a p:dialog

I currently have a giant ui:repeat. Within this ui:repeat, some of the repeated objects have a url to a popup image associated with them. When someone clicks display under that particular object, I need the url to popup in a p:dialog.
<ui:repeat var="thing" value="#{bean.thingList}">
<p:commandLink value="details" onclick="miniImage.show();"
update=":#{p:component('chart')}"
action="#{bean.setCurrentImg(thing.imageUrl)}"
rendered="#{thing.includeImage}">
</p:commandLink>
</ui:repeat>
and at the bottom of the page:
<p:dialog id="chart" widgetVar="miniImage" >
<h:graphicImage value="#{bean.currentImg}"/>
</p:dialog>
And in the backing bean I tried using a simple setter and getter for currentImg.
I am a bit confused on this now and would like to accomplish this without having to submit the entire form as well. Any help is greatly appreciated.
If you're using PrimeFaces 3.3 or newer, you could just add partialSubmit="true" to the command component. You can then control the to-be-processed components in process attribute. In this particular case, just the current component (the command component itself) is sufficient, thus so process="#this":
<p:commandLink ... process="#this" partialSubmit="true" />
This way only the request parameters which are really necessary for the process will be sent.
Unrelated to the concrete problem, I suggest to use oncomplete instead of onclick to open the dialog. Otherwise the dialog is opened before update takes place and may cause poor user experience as the enduser would see the image instantly changing.

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

render richfaces popupPanel after bean method is finished

I have a simple problem where I want to display a popup if something went wrong in my managed bean.
The bean holds a list of exceptions that can be raised, with getter/setter methods.
The xhtml looks like this
<rich:panel>
<h:form>
<a4j:commandButton value="Compute Mission"
action="#{missionHandler.generateMissionFeasability}"
render="popupPanel">
</a4j:commandButton>
</h:form>
</rich:panel>
<rich:popupPanel id="popupPanel" modal="true" autosized="true"
resizeable="false" moveable="false" rendered="#{not empty missionHandler.exceptions}">
<f:facet name="header">
<h:outputText value="Exceptions raised during the processing " />
</f:facet>
<f:facet name="controls">
<h:outputLink value="#"
onclick="#{rich:component('popupPanel')}.hide();return false;">
</h:outputLink>
</f:facet>
</rich:popupPanel>
As you see I have a command button that should call generateMissionFeasibility method in the bean.
The method will (among other things) add exception in the exceptions list.
I would like to check the list (if it's empty or not) to display the popup
The code above doesn't work because I think the popup is rendered before the end of the method in the bean, and the list is empty at the beginning.
One way to make popup panel be shown once rendered is to change
rendered="#{not empty missionHandler.exceptions}"
to
show="#{not empty missionHandler.exceptions}"
The code doesn't work because the first time the view is about to be rendered, missionHandler.exceptions will be empty, which means popupPanel never makes it to the browser. Subsequent requests to reRender popupPanel will fail as the component is nowhere to be found in the DOM.
For a component to be ajax-updated, it must already be in the DOM in the browser, this is the way ajax works. So the solution is to wrap the content of the popup panel in a component that will always be rendered.
That aside, even if you got the rendering correct, your popup will only be placed in the DOM. You actually need to call show() on the popup to get it to showup
To achieve what you want however, a better alternative will be to
Conditionally display the popup using javascript. If the condition is met, the show() function is called for the popup. Otherwise, an empty, do-nothing javascript function will be called.
<a4j:commandButton value="Compute Mission" action="#missionHandler.generateMissionFeasability}"
oncomplete="#{not empty missionHandler.exceptions ? #{rich:component('popupPanel')}.show()" : doNothing()}" render="popupPanel">
</a4j:commandButton>
For the doNothing js:
<script> function doNothing(){} <script/>
Take the rendering condition out of the modal panel
EDIT: Additionally, the show attribute on the popup component can be based on the same EL condition as the oncomplete attribute

Resources