So we have an f:event:
<f:metadata>
<f:event type="preRenderView" listener="#{dashboardBacking.loadProjectListFromDB}"/>
</f:metadata>
Which is triggered as desired on initial page load (render).
However this preRenderView event is also triggered by an ajax partial page render, which re-renders an h:panelgroup with the id projectListing, as below.
<h:commandButton action="#{mrBean.addProject}" value="Create Project"
title="Start a new proje开发者_如何学Goct">
<f:ajax render="projectListing" />
</h:commandButton>
I only want the dashboardBacking.loadProjectListFromDB to be called for the initial page render, but not when there is an ajax partial render. Is there a more appropriate event or method I could be using?
I had the same need not too long ago. I ended up using something suggested by BalusC.
There is a method in the FacesContext class that lets you know if you're dealing with a full blown request or a partial processing of some sort:
FacesContext.getCurrentInstance().isPostback()
This way you can still use the preRenderView technique and check if it's a postback in the listener. I found that particularly useful because I needed a session bean as the user had to navigate to another page and come back. If I used view scoped beans (like suggested above by Brian), I'd lose the info I had before navigating away.
Another option would be to put your preRenderView
functionality in a @PostConstruct
method of a ViewScoped
managed bean. This logic would be executed when the bean is initialized, and you you maintain the same instance of the bean for all your ajax requests until you change views.
Another possibility is to check if the request is an ajax one or not in the preRenderView method. You can also perform the load conditionally considering other factors such as if the request is a GET or not and if validation failed or not (view params validation can fail on GET page).
boolean getMethod = ((HttpServletRequest) fc.getExternalContext().getRequest()).getMethod().equals("GET") ? true : false;
boolean ajaxRequest = fc.getPartialViewContext().isAjaxRequest();
boolean validationFailed = fc.isValidationFailed();
The "new-age" way of handling this is described here:
http://www.coderanch.com/t/509746/JSF/java/duplicate-call-preRenderView-event#2634752
You could try attaching the preRenderView event listener to an individual component, rather than the page. Choose a component that is not rendered during an Ajax request.
One small problem is that the view parameters have not been set when the @PostConstruct method is called so I had to get them explicitly:
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("theParam");
update: actually, I ended up doing the @PostConstruct thing, its much cleaner.
I had exactly the same issue today with a session-scoped backing bean. Namely, I had registered an event-listener method on the backing session-scoped bean that was registered with the preRenderView. But I found that it was also fired on some Ajax sorting operations on a PrimeFaces 3 dataTable component. So, what I ended up doing was using a boolean instance variable on the session-scoped backing bean to make sure the body of the event-listener method executed only the first time (the boolean acted as a flag). I am sure it's rather naive and probably broken on certain cases so I would be interested to know why and how this simplistic approach might fail.
精彩评论