Navigate to previous page with JSF - jsf

I use a backing bean where I can save a form and navigate to this page.
public String saveHere() {
return Faces.getViewId() + "?faces-redirect=true&includeViewParams=true";
}
How do I navigate to the previous page with OmniFaces?
My save action should result in the page where I have the "edit" button.
Typically a list-view (with edit-button next to very item)
or another page with (with edit-button to this item)
Thanks!

You need the page id you're navigating from somewhere. At first look, keeping it in Session seems to be a good idea, however, this could remain in coflict if you're navigating in multi-tab (sharing same Http Session through different browser tabs).
Having said that, the most proper solution for your case is to pass a view param to your edition view telling where you're coming from. That should be as easy as this:
<h:button outcome="edit" value="Edit registry">
<f:param name="pageFrom" value="#{view.viewId}" />
</h:button>
After that, in your edition view bind this param to your bean:
<f:metadata>
<f:viewParam name="pageFrom" value="#{editBean.pageFrom}" />
</f:metadata>
And just redirect to that view in your EditBean.java after saving, supposing it is #ViewScoped:
public String saveHere() {
//save here
return pageFrom + "?faces-redirect=true&includeViewParams=true";
}
That's the most straight forward way to achieve what you ask for. However, you must take into account the page where you're coming from remains to be a view parameter, so the end user could type what he wants there. With this behaviour, he could achieve being redirected to some other page rather than the one expected. If you want to avoid that, go with the flash scope instead of view parameters.
See also:
Get current page programmatically

Related

h:commandButton with an action and then page-navigation in JSF?

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}"/>

Bean's method that returns to the previous page

After performing the appropriate action, the method of my bean must ensure that the browser back to the previous page. How can I handle it?
I am using the CDI Conversation.
Pass the current URI as request parameter along during navigation to the page containing that action.
<h:link value="Go to page containing that action" outcome="pageContainingThatAction.xhtml">
<f:param name="from" value="#{request.requestURI}" />
</h:link>
(use #{view.viewId} instead if you want to pass the view ID)
Set and remember that parameter representing the URI in the view/conversation scoped managed bean.
<f:metadata>
<f:viewParam name="from" value="#{bean.from}" />
</f:metadata>
Finally redirect to that URI in that action method.
public void thatActionMethod() throws IOException {
// ...
externalContext.redirect(from);
}
After asking you a couple of question in comments, I think what you want to do is :
On your button, specify the attribute action to a function in your bean that return a String.
The String returned need to be the navigation path to the page you want to be redirected.
If the validation is wrong on button click, then simply return null and it will stay on same page.
Make sure you define the proper navigation rule in faces-config.xml
See this tutorial for how to configure navigation rules.
See Primefaces commandButton doc for info on action tag.

Get url parameter into facelets view after user session timeout

I am building a CRUD web application using JSF. I have a problem with loading a page after the user session has timed out. That is i lose the parameters I need to construct the view (even though the parameters are still visible in the url like so: 'someurl/view.xhtml?pid=5'.
In the .xhtml file the parameter pid is used to load some content from an underlying database when constructing the view. When the user has been inactive for a while their session times out, and if they try to reload the page in the browser they are forwarded to the login page (the 'someurl/view.xhtml?pid=5' still intact) and on succesful login go back to the view.xhtml page where I wan't the view to be constructed as if their session had never timedout.
However this does not happen because the 'pid' parameter is no longer set in the view. But since the 'pid' parameter is still visible in the url I feel like I should be able to get it into the view and load the protein with this id from the database.
These are the things I've tried:
#{protein.setProteinById(param.pid)}
and
#{protein.setProteinById(param['pid'])}
and
#{protein.setProteinById(request.getParameter('pid'))}
and
<c:set value="${request.getParameter('pid')}" var="pid" />
#{protein.setProteinById(pid)}
Is this possible to do? Then how?
I'm no expert, but wouldn't you set it in the managed bean?
As far as I know there are two methods for doing this.
One method is using in your facelet to push a view parameter back into a bean (I have a scenario where this doesn't work because of other things, so have no experience with it)
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
I have a prerender method, which is always called before a render
<f:metadata>
<f:event type="preRenderView" listener="#{MyController.prerenderMethod}" />
</f:metadata>
And inside the method, I look at the parameters:
public void prerender(ComponentSystemEvent event) {
value = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("key");
}

How to open a blank page for an external url with JSF, if target url must be initialy retained from server?

Primefaces 3.5.14, Omnifaces 1.6
Is there a component in JSF/Prime that looks like a button, but that allows to open a new blank page with an external link ? So unlike a normal link, on click the new page URL must be initialy retained from server and just then new page must be opened. Like a commanButton with an action attribute, where a string result of an action method determine the new url.
Of course I can use p:button as in Styling one JSF external link to make it look like a button but in that case I must update link generated by p:button, depending on actions made on the page every time. This is not always desirable.
You need target="_blank" on the parent form in order to submit into a new window and you need to invoke ExternalContext#redirect() (or OmniFaces' Faces#redirect()) in the action method in order to let the target window send a new GET request on the given URL. Importantly, when you use <p:commandButton> instead of <h:commandButton>, you also need to set ajax="false" because it doesn't respect target="_blank".
Thus, so:
<h:form target="_blank">
<p:commandButton value="Submit" action="#{bean.submit}" ajax="false" />
</h:form>
with
public void submit() throws IOException {
String redirectURL = determineItSomehow();
Faces.redirect(redirectURL);
}

How do I update a menu bar in a calling template

As an exercise I want to have a menu bar which is disabled until the user logs in. When he logs in I want to call something which will trigger an update. The menu bar is in the master.xhtml template file
<h:form >
<p:menubar id="masterMenuBar">
<p:menuitem disabled="#{backing.disableMenu}" value="List users" />
</p:menubar>
</h:form>
As part of the login I have code to refresh the form
public void refreshForm() {
RequestContext context = RequestContext.getCurrentInstance();
context.update("form1");
context.update("masterMenuBar");
}
I tried my luck with calling a context update to my defined label of masterMenuBar but the RequestContext apparently doesn't include my calling template form (which sounds reasonable enough).
Is there some other context I can call which will include a context update to my menu bar? Perhaps I am on the wrong path, and there is a better way to achieve the same thing?
I did notice that even resizing the browser wasn't reason enough to call again to my backing.disableMenu bean. Apparently I need something fairly strong to cause it to reach my bean a second time.
You need to pass the absolute client ID, not the relative client ID. If you rightclick and view source in browser, then you'll see that the masterMenuBar element has the (autogenerated) ID of its form prefixed.
You need to give the form where the menu is sitting in a fixed ID
<h:form id="menuForm">
<p:menubar id="masterMenuBar">
...
and pass the absolute client ID instead.
context.update("menuForm:masterMenuBar");
Update: sorry, it shouldn't start with : in contrary to the update attribute of <p:commandButton>.

Resources