问题
I am trying to execute a JSF2 bean method and show a dialog box after completion of the method on click of PrimeFaces <p:commandButton>
.
<p:commandButton id=\"viewButton\" value=\"View\"
actionlistener=\"#{userBean.setResultsForSelectedRow}\" ajax=\"false\"
update=\":selectedRowValues\"
oncomplete=\"PF(\'selectedRowValuesDlg\').show()\">
</p:commandButton>
<p:dialog id=\"selectedRowValues\" widgetVar=\"selectedRowValuesDlg\" dynamic=\"true\">
<h:outputText value=\"#{userBean.selectedGroupName}\" />
</p:dialog>
When I click on the command button, the bean action listener method setResultsForSelectedRow
executes properly, but it does not show the dialog box when the method completes. If I remove actionlistener
, it shows the dialog box. I do not know what is going wrong.
What is the execution order of events? Is it possible to execute actionlistener
and oncomplete
simultaneously?
回答1:
It failed because you used ajax="false"
. This fires a full synchronous request which in turn causes a full page reload, causing the oncomplete
to be never fired (note that all other ajax-related attributes like process
, onstart
, onsuccess
, onerror
and update
are also never fired).
That it worked when you removed actionListener
is also impossible. It should have failed the same way. Perhaps you also removed ajax="false"
along it without actually understanding what you were doing. Removing ajax="false"
should indeed achieve the desired requirement.
Also is it possible to execute actionlistener and oncomplete simultaneously?
No. The script can only be fired before or after the action listener. You can use onclick
to fire the script at the moment of the click. You can use onstart
to fire the script at the moment the ajax request is about to be sent. But they will never exactly simultaneously be fired. The sequence is as follows:
- User clicks button in client
onclick
JavaScript code is executed- JavaScript prepares ajax request based on
process
and current HTML DOM tree onstart
JavaScript code is executed- JavaScript sends ajax request from client to server
- JSF retrieves ajax request
- JSF processes the request lifecycle on JSF component tree based on
process
actionListener
JSF backing bean method is executedaction
JSF backing bean method is executed- JSF prepares ajax response based on
update
and current JSF component tree - JSF sends ajax response from server to client
- JavaScript retrieves ajax response
- if HTTP response status is 200,
onsuccess
JavaScript code is executed - else if HTTP response status is 500,
onerror
JavaScript code is executed
- if HTTP response status is 200,
- JavaScript performs
update
based on ajax response and current HTML DOM tree oncomplete
JavaScript code is executed
Note that the update
is performed after actionListener
, so if you were using onclick
or onstart
to show the dialog, then it may still show old content instead of updated content, which is poor for user experience. You'd then better use oncomplete
instead to show the dialog. Also note that you'd better use action
instead of actionListener
when you intend to execute a business action.
See also:
- Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
- Differences between action and actionListener
回答2:
I just love getting information like BalusC gives here - and he is kind enough to help SO many people with such GOOD information that I regard his words as gospel, but I was not able to use that order of events to solve this same kind of timing issue in my project. Since BalusC put a great general reference here that I even bookmarked, I thought I would donate my solution for some advanced timing issues in the same place since it does solve the original poster's timing issues as well. I hope this code helps someone:
<p:pickList id="formPickList"
value="#{mediaDetail.availableMedia}"
converter="MediaPicklistConverter"
widgetVar="formsPicklistWidget"
var="mediaFiles"
itemLabel="#{mediaFiles.mediaTitle}"
itemValue="#{mediaFiles}" >
<f:facet name="sourceCaption">Available Media</f:facet>
<f:facet name="targetCaption">Chosen Media</f:facet>
</p:pickList>
<p:commandButton id="viewStream_btn"
value="Stream chosen media"
icon="fa fa-download"
ajax="true"
action="#{mediaDetail.prepareStreams}"
update=":streamDialogPanel"
oncomplete="PF('streamingDialog').show()"
styleClass="ui-priority-primary"
style="margin-top:5px" >
<p:ajax process="formPickList" />
</p:commandButton>
The dialog is at the top of the XHTML outside this form and it has a form of its own embedded in the dialog along with a datatable which holds additional commands for streaming the media that all needed to be primed and ready to go when the dialog is presented. You can use this same technique to do things like download customized documents that need to be prepared before they are streamed to the user's computer via fileDownload buttons in the dialog box as well.
As I said, this is a more complicated example, but it hits all the high points of your problem and mine. When the command button is clicked, the result is to first insure the backing bean is updated with the results of the pickList, then tell the backing bean to prepare streams for the user based on their selections in the pick list, then update the controls in the dynamic dialog with an update, then show the dialog box ready for the user to start streaming their content.
The trick to it was to use BalusC's order of events for the main commandButton and then to add the <p:ajax process="formPickList" />
bit to ensure it was executed first - because nothing happens correctly unless the pickList updated the backing bean first (something that was not happening for me before I added it). So, yea, that commandButton rocks because you can affect previous, pending and current components as well as the backing beans - but the timing to interrelate all of them is not easy to get a handle on sometimes.
Happy coding!
来源:https://stackoverflow.com/questions/20146630/execution-order-of-events-when-pressing-primefaces-pcommandbutton