JSF request attribute - jsf

I am using JSF 1.2. I have a page with a button. The action hooked to the button adds a request attribute to the request object and navigates to page2. On page2 I try to retrieve that attribute with #{requestScope.attr}. But this doesn't work. Any ideas why?
Thx.

Apparently page2 was requested by a different HTTP request. That can happen if you have sent a redirect instead of a forward when the action method is finished. For example, by calling ExternalContext#redirect() in the action method or by adding <redirect /> to the navigation case. A redirect basically instructs the browser to create a brand new HTTP request.
That said, I wonder how it's useful to explicitly set a request attribute if you're already using JSF. Just assign the desired data as a property of the current bean (which I assume to be just request scoped).
private String foo; // +getter
public String submit() {
foo = "some value";
return "nextpage";
}
This way it's just available by #{bean.foo} in the next page.
<h:outputText value="The value is: #{bean.foo}" />

Related

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.

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);
}

CommandButton open new tab with FlashScope parameters

How can I open new tab when user clicks p:commandButton? I also want to pass some parameters to new page using FlashScope. Here's the code:
<h:form>
<p:commandButton value="open new tab" action="#{myBean.newTab}"/>
</h:form>
public String newTab() {
Faces.setFlashAttribute("foo", bar);
return "otherView";
}
On the otherView page I use f:event type="preRenderView" to read Flash parameters.
Two notes:
I need to use FlashScope, not URL parameters.
If possible, I don't want to change newTab() and preRenderView() methods.
Thanks for help
Use target="_blank" on the form to tell the browser that the synchronous response of the form should be presented in a new (blank) tab/window. You only need to turn off ajax behaviour of the <p:commandButton> in order to make it a synchronous request.
<h:form target="_blank">
<p:commandButton value="open new tab" action="#{myBean.newTab}" ajax="false" />
</h:form>
No changes are necessary in the backing beans, it'll just work as you intented. I would only recommend to use POST-Redirect-GET pattern in the action method.
return "otherView?faces-redirect=true";
Otherwise the new tab would show the URL of the originating page and a F5 would re-invoke the POST. Also, this way the flash scope is also really used as it is been designed for (if you didn't redirect, just storing in request scope was been sufficient).
Update: as per the comments, the view scoped bean in the initial tab/window get killed this way. by returning a String navigation case outcome. That's right, if you'd like to keep the view scoped bean alive, replace the navigation case by a Faces#redirect() call (assuming that it's indeed OmniFaces which you're using there for Faces#setFlashAttribute()). You only need to set Flash#setRedirect() to true beforehand to instruct the flash scope that a redirect will occur.
public void newTab() throws IOException {
Faces.setFlashAttribute("foo", bar);
Faces.getFlash().setRedirect(true);
Faces.redirect("otherView.xhtml");
}

further continuing of double press

In a previous question BalusC gave me good advice on how a button, in place of a commandButton is useful for non ajax navigation. In particular it updates the destination address in the http: position which is useful for the user to bookmark a page.
I tried to use this information to my advantage until I came upon a problem. In a button I tried to use outcome="#{backing.something}" to find out that it gives me a null result. This looks like a timing problem in that action="#{}" is evaluated only when the button is pressed whereas outcome apparently wants a fixed string which gets checked when the page is loaded.
So I went back to commandButton with ajax="false". This has a problem that my navigation address is the page I came from, not the one I am navigating to. This is the wrong bookmark for the user.
I appreciate all the help I have received in stackoverflow on my learning exercise.
Ilan
The <h/p:button outcome> is not intented to invoke a bean action method, but to contain the outcome string directly. Any EL in there is evaluated immediately as a value expression. So the method behind it would immediately be invoked when you just open the page containing the <h/p:button>.
There are in your particular case basically two ways to invoke a bean action method on navigation. If you need to invoke it before the navigation takes place and the action isn't intented to be re-invoked everytime when the enduser reopens/reloads the GET request, then make it a POST-Redirect-GET request. It's a matter of adding faces-redirect=true to the outcome value in query string syntax.
E.g.
<p:commandButton action="#{bean.submit}" ... />
with
public String submit() {
// ...
return "nextpage?faces-redirect=true";
}
This way the browser will be redirected to the target page after POST, hence the enduser will see the target URL being reflected in the address bar.
Or if you need to invoke the action everytime when the enduser reopens/reloads the GET request, do the job in the (post)constructor or preRenderView listener method of the request/view scoped backing bean instead.
E.g.
<p:button outcome="nextpage" ... />
with
#ManagedBean
#RequestScoped
public class NextpageBacking {
public NextpageBacking() {
// In constructor.
}
#PostConstruct
public void onPostConstruct() {
// Or in postconstructor (will be invoked after construction AND injection).
}
public void onPreRenderView() {
// Or before rendering the view (will be invoked after all view params are set).
}
// ...
}
The pre render view listener method needs to be definied as follows in the nextpage
<f:event type="preRenderView" listener="#{nextpageBacking.onPreRenderView}" />
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Communication in JSF 2.0 - Processing GET request parameters

Redirecting to an external URL in a new tab and performing an action in backing bean at the same time

I'm working at a jsf application that at a certain time need to open an external page in a new tab, leaving the first page active. I need to find a way to make the application perform, in a single button click:
a redirect to an external URL in a new tab
an action which disables the button itself in the original page
I've tried using an <outputLink /> but it has no action attribute.
I've tried using a <commandLink />but it's unable to redirect outside.
I've also tried a <commandLink /> with target="_blank" and a redirection coded in the backing bean:
<h:commandLink onclick="submit();" target="_blank" action="#{myBean.execute}" disabled="#{myBean.linkDisabled}" value="external link" />
and, in the backing bean:
public String execute() {
linkDisabled = true;
try{
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.redirect(Constants.EXTERNAL_URL);
} catch(Exception e){
throw new FacesException("Redirection failed");
}
return THIS_PAGE;
}
A page is opened in a new tab but it's the current page instead of the that with URL Constants.EXTERNAL_URLand the button is still enabled. No error message is shown. Any suggestion?
Thanks in advance, Andrea
Your question is confusing. You're mixing "link" and "button". You basically need to disable the element in the client side by JavaScript because the response does not return to the current browser window/tab, but to a different browser window/tab. In JavaScript, it's easy to disable a button, but not a link. For simplicity, I'll assume that you mean and can use a <h:commandButton> and that this is the only button in the current form.
To solve your problem, you need to remove onclick="submit()" (because it's disturbing the default behaviour) and you need to remove the navigation outcome (it should not matter, but you never know in some JSF impls) and you need to disable the button by JS in the client side.
All with all your code should look just like this:
<h:form target="_blank">
<h:commandButton
value="external"
action="#{myBean.execute}"
onclick="setTimeout('document.getElementById(\'' + this.id + '\').disabled=true;', 50);" />
</h:form>
And
public void execute() throws IOException {
FacesContext.getCurrentInstance().getExternalContext().redirect(Constants.EXTERNAL_URL);
}
The setTimeout() is necessary because the button is otherwise disabled before the form data is sent which would cause that the button's own name=value pair won't be sent as request parameter and so JSF won't invoke any action.
why don't you use action="someaction" and map it in faces-config.xml to go to another page?

Resources