Hello,
I have a requirement, to perform some functionality before the user navigates away from current page (navigation may be either by forward or redirect).
So I thought I'd use this system event called PreRemoveFromViewEvent on any one of the components on the page.
PreRemoveFromViewEvent has always been a theoretical concept to me, I never used it practically.
So I applied this event on h:inputText and thought that it will fire the event when user navigates away from page and this h:inputText will be removed from view before loading the new page/view.
But this is not firing.
Am I using it right?
Am I using it on right component?
Will it serve the purpose of firing event before navigating away?
Here is my code:
<h:inputText id="abc">
<f:event listener="#{myManagedBean.preRemoveFromViewHandler}"
type="javax.faces.event.PreRemoveFromViewEvent"/>
</h:inputText>
<p:commandButton action="page2.xhtml" value="NEXT"/>
Listener:
public void preRemoveFromViewHandler(PreRemoveFromViewEvent prfve){
//USER is navigating away so save the data
}
USING: JSF Mojarra 2.1.13 | Primefaces: 3.5
You should be using the PreDestroyViewMapEvent instead, registered within the <h:body/> or <f:view/>. This event is the one that's fired when one is navigating away from a view. From the specification:
Immediately before the Map is destroyed, a PreDestroyViewMapEvent must be published using UIViewRoot as the event source
The PreRemoveFromViewEvent is fired only when the parent component is removed from the viewmap, something that doesn't necessarily happen when a the navigating away from the page.
Related
I'm trying to use an InputFile within JSF (1.1.7) and Apache Trinidad (1.0.11). I define a change event for it but the event is not being fired when I change the file selection but when I click on another component of the form.
Here is the jsp code:
<trh:body>
<tr:panelPage>
<tr:form usesUpload="true" id="myForm">
<tr:inputFile columns="80" id="archivo"
valueChangeListener="#{myBean.changeInputFile}"
immediate="true">
</tr:inputFile>
<tr:commandButton text="Begin"/>
</tr:form>
</tr:panelPage>
</trh:body>
Here is the relevant part of the bean:
public void changeInputFile(ValueChangeEvent event) {
UploadedFile f = (UploadedFile)event.getNewValue();
}
The code only enters into the myBean.changeInputFile method when I click the Begin button (having changed the file selection previously). I would like it to enter into myBean.changeInputFile when I change the selected file in the inputFile component.
Any idea why could be this happening?
Your expextation is wrong. The valuechangelistener is a server-side action that will fire when something is submitted to the server and effectively has a different value than it did before. It is NOT telling the component to behave like modern ajax (jsf 1.1.7 and its valuechangelistener predate the ajax era). The form value is only submitted to the server when you, well, in 'old' html terms use form submission like pressing a submit button (or use some javascript to trigger that like you would in the old plain html days). And since without pressing a button or the added javascript, nothing is submitted to the server the valuechangelistener will not spontaneously do something.
So the behaviour you see is exactly as it should be.
Is it possible to have a commandButton that executes a method of a certain backing bean and then also navigates to a different page?
I know that I could return a String in the method that the commandButton calls, but the method is also used on the target-page, meaning it's often called from that same page.
So for calls that come from the same page, the redirect would be unnecessary and I would like to avoid that.
The options that I have in mind right now:
Create a separate method for the "remote" call of the method that does the same logic and also redirects to the page
Use an additional h:button and use JavaScript so that if the commandButton is pressed, the h:button is pressed at the same time (Probably bad practice tho)
Any option I am missing? Is there any way to tell the commandButton itself that it's supposed to navigate somewhere or do I have to implement this in the backing-beans?
Your title and first sentence are 'dangerous' and sort of not on topic since to both, the answer is yes and you sort of describe (= answer) that in your second paragraph already yourself.
The real question further on effectively asks about conditional navigation. But let me state first that your solution of two methods is also not wrong if you just make sure you don't do actual work in the bean (which you should not).
Now conditional navigation is by itself not difficult
returning null (to stay on the same page) without a refresh, "" to stay on the same page with a refesh,
return the new page (with redirect).
All basic JSF which I assume you are already aware of and this just requires something to do one or the other
So then the question remains if you can
detect the page you are on when the method is executed or
pass on a parameter to the action
which in turn can be used to return null or the other new page in an if/else.
Page1:
<h:commandButton action="#{mybean.action(true))" />
Page2:
<h:commandButton action="#{mybean.action(false))" />
Bean:
public String action(boolean navigate) {
doWork();
if (navigate) {
return "page2.xhtml?faces-redirect=true";
} else {
return null;
}
And if you'd want it, you could even pass null or the page name as a parameter to the method call.
Implementing detection of the source page of the action has the advantage that in the UI you do not need any knowledge on how to navigate, you always call the same method without any parameters and each new page you'd use this action on navigates to the right page without the developer needing any knowledge.
So take you pick.
I'm not completely sure if I got you right, but you could do something like this:
<h:commandButton value="Click" action="otherPage.xhtml?faces-redirect=true">
<f:actionListener binding="#{bean.method}" />
</h:commandButton>
Keep in mind that actionListener will be fired first and after that action from commandButton. Hope it helps.
Update:
Due to the fact that there was no further thinking you can use commandButton with or without redirect.
<h:commandButton value="Click" action="{bean.method}"/>
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?
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 executed
action 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
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
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!
I have a <h:panelGrid> and a h:commandLink(link is basically a image).Now I want that on mouseover event , Then link should be render(render='true') and on mouseout event, it gets removed render='false'.But I am unable to create the logic that How can I do this with these events as the approach I am using is To set the values of bean true and false on this event.
Here is my code
<h:form>
<h:panelGrid mouseover='** we cannot call a bean method here which changes the bean value **'>
This is the Div On which I want to apply mouseover event
</h:panelGrid>
<h:commandLink id="btn" render={renderBean.renderLink}>
<h:graphicImage url="image.jpg"/>
</h:commandLink>
</h:form>
The default value of renderLink attribute of renderBean is false. Now I want to know the way that How can I change its value to true on mouseover event? Is it possible? OR Anyother solution in JSF w.r.t this requirement
You have to remember in JSF that the page will first be processed server-side by the JSF engine in the web server. At that time all JSF tags will be converted into their HTML equivalent. The render attribute tells the server-side engine whether or not to output an HTML a (anchor) link in the place of the <h:commandLink> element.
The behavior you're looking for, namely responding to mouse events, is client-side functionality. It happens in the browser, not at the web server, so no JSF is involved. The solution is to handle the mouse events in JavaScript, not JSF. You will typically set (or remove) the CSS attribute display:none on the id called btn (unfortunately it's slightly more complex as JSF will mangle the element id a bit). There are lots of posts here on StackOverflow that deal with how to handle client-side events in JavaScript. Using jQuery for example is a really common approach.
I recommend to get started you take a look at the blog of one of our best JSF resources and long-time StackOverflow user BalusC: http://balusc.blogspot.com.
There's a lot to learn and you'll get a good start by going there first (and searching for his posts on SO).
Good luck.
I am trying to popup a window when someone clicks a button on the data table.
<h:commandButton
action="#{cacheController.popupDetails}"
immediate="false"
onclick="popup()"
value="View Details"
styleClass="submit">
</h:commandButton>
The associated popup function is
function popup() {
window.open('RDDetails.jsf','popupWindow', 'dependent=yes, menubar=no, toolbar=no, height=500, width=400');
}
Now in the new 'RDDetails.jsf" file, I am trying to access the same managedBean cacheController. But the problem is, the pop-up window and JSF lifecycle is not in sync. As a result, the popup first displays blank and when I refresh, it pulls out the proper data.
Is there anyway I can click on a button which will do some processing in the managed bean and then opens a pop up which rerieves the processed data from the managed bean.
I am using JSF 1.1.
You're here basically firing two independent requests: one associated with the form submit and other which opens the RDDetails.jsf in a popup. You'll need to combine this in one request. You can achieve this in basically two ways:
Get rid of the onclick and just add target="_blank" to the <h:form> so that it get submitted into a new window/tab.
Block the default action by adding return false; to the onclick and do the business logic in the constructor of the bean associated with RDDetails.jsf. The only (major) caveat is here that the model won't be updated with the form fields. Thus, you'll need to pass the form fields as request parameters of the popup URL manually with help of JavaScript. You can then make use of managed property entries in the faces-config.xml to inject the GET request parameters into the model.
First way is obviously the easiest, but this doesn't give you a "fullworthy" popup/modal dialog. The second way is a bit harder (unless you've already a good grasp on both JavaScript and JSF). I would then consider to look for a component library which provides a ready-to-use popup component.
See my example:
<h:commandLink action="#{controller.myAction}" onmousedown="document.forms['idform'].target='_blank';">
I'm using jsf 1.1