I need to send some parameters from one xhtml to another, but I don't want these parameters to appear in the URL. How to do that? I could use p:commandLink, but then I don't know how to open the destination page from the bean method. The destination page should be accessible by friendly URL, not by xhtml name.
This code will open the page /users/view. How can I send parameters without them appearing in the URL?
<h:outputLink value="/users/view">
<h:outputText value="#{entry.employee}" />
</h:outputLink>
Ignoring the strange design, you could use put the data in the flash scope and send a redirect in a <h:commandLink> action method:
public void view() throws IOException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.getFlash().put("employee", employee);
ec.redirect(ec.getRequestContextPath() + "/users/view");
}
And then in the backing bean associated with the target page:
#PostConstruct
public void init() {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
employee = (Employee) ec.getFlash().get("employee");
}
See also:
Pass an object between #ViewScoped beans without using GET params
What is the difference between redirect and navigation/forward and when to use what?
Related
I have the following issue:
I have a page on which I create a offer (page1).
Now I have a button on page1 to select a customer (page2).
So I press the button and my new page (page2) appears to select a customer.
With another button I select the customer and redirect to my first page (offer page). But now all my entered values are not there anymore.
I tried the following:
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.context.SessionScoped;
import javax.faces.view.ViewScoped;
My button is the following:
<p:commandButton value="Select customer" ajax="true" process="#all"
actionListener="#{offerEditController.doSelectCustomerForDocument}"
update=":addOfferForm, growl" immediate="true">
</p:commandButton>
And here my method for go to the page2:
public void doSelectCustomerForDocument() {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + Constants.CUSTOMER_LIST
+ "?create_document=/offerEdit.jsf&document_id=" + offer.getId());
}
#SessionScoped works not for all inputFields, e.g.
For
<p:inputText id="offer_subject"
value="#{offerEditController.offer.title}" >
<p:ajax events="blur" update="offer_subject_panel"
global="false" />
</p:inputText>
Any ideas how can I solve this? I know I could use a p:dialog, but I donĀ“t like this.
Thank you for all help.
The better ideia would use a p:dialog, because it fits perfectly on your case but if you don't like it, you should improve the way you call your pages. In your case, when you do the following:
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + Constants.CUSTOMER_LIST
+ "?create_document=/offerEdit.jsf&document_id=" + offer.getId())
you force the page to reload and recall the #PostConstruct method, cleaning the whole backing bean (controller). That's why you lose the values entered.
If you want to keep this approach of redirection you have to store the page data somewhere before it get cleaned. I suggest storing at requestContext passing parameters using JSON from page2 to page1 using <p:remoteCommand>, then, when you reload on #PostConstruct method you look for parameters in the requestContext and reset the fields.
Put this on Page2:
<p:commandButton id="buttonOnPage2" onclick = "remoteCommandFunction([{name:'value1',value:'#{bean.value1}'},{name:'value2',value:'#{bean.value2}'}])"/>
<p:remoteCommand name="remoteCommandFunction" actionListener="#{bean.storeData()}"/>
On your bean:
public void storeData(){
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
if(params.get("value1") !=null && !params.get("value1").isEmpty())
this.value1= params.get("value1");
if(params.get("value2") !=null && !params.get("value2").isEmpty())
this.value2= params.get("value2");
}
You have to ensure that storeData() method is called after #PostConstruct, if its called after post construct, everything will be null. If this happens you should put the storeData() method in a #SessionScoped bean and retrieve it on your #ViewScoped inside #PostConstruct method like this:
#PostConstruct
public void init(){
...
this.value1 = getSessionScopedBean().getValue1();
this.value2 = getSessionScopedBean().getValue2();
getSessionScopedBean().setValue1(null);
getSessionScopedBean().setValue2(null);
}
Imagine this situation:
I have a SessionScoped bean (named TheSessionBean) that is a ManagedProperty of another bean (named AnotherBean).
#ManagedBean
#ViewScoped
public class AnotherBean implements Serializable {
#PostConstruct
public void init() {
//Evaluate here!
}
#ManagedProperty(value = "#{theSessionBean}")
private TheSessionBean theSessionBean;
//Getter and Setter...
}
I need to evaluate the value of the ManagedProperty (theSessionBean) in order to know if a page can be showed without the user interaction and before the page is shown.
As I understand this must be evaluated in the PostConstruct method (so I can get the value of the Session of the ManagedProperty).
TheSessionBean has only a String property named permission.
So first of all I need to know if:
theSessionBean.getPermission() == null in order to redirect to a page named one
theSessionBean.getPermission().equals("two") in order to redirect to a page named two
More evaluations...
The problem is that the PostConstruct method must be void and I need to redirect to the corresponding page.
How can I do that?
You can use ExternalContext.redirect in your PostConstruct method.
if (someCondition)) {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.redirect(ec.getRequestContextPath() + "/one");
}
Best practice is to use JSF system events- PreRenderViewEvent PostConstructApplicationEvent PreDestroyApplicationEvent
JSF events
I have two different pages. In the first page I have a Map in a ViewScoped Bean, and in the second page there is another ViewScoped Bean that needs the Map in the first page. How can I pass the Map between the two pages?
I've thought of transforming the Map into a JSON string, and passing through <f:viewParams>, but that might make the url too long.
Any ideas will be appreciated!
Given that the second page is been opened by a PRG request, your best bet is to make use of the flash scope. You can put flash scoped attributes in the map as available by ExternalContext#getFlash() and you can get them in the next request by the very same ExternalContext#getFlash() map (which is in EL scope also available by #{flash}).
So, e.g. this should do: in the action method of backing bean of first page:
public String submit() {
// ...
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.getFlash().put("data", data);
return "page2?faces-redirect=true";
}
And then a property of backing bean of second page (page2):
#ManagedProperty("#{flash.data}")
private Map<String, String> data; // Setter required.
Or, alternatively, the postconstruct of backing bean of second page:
private Map<String, String> data;
#PostConstruct
public void init() {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
data = (Map<String, String>) ec.getFlash().get("data");
}
I have a logout link in my JSF app that invalidates the session to log the user out. It works but it doesn't redirect the user to the logon page. It stays on the same page. If I try to access the same page again it does direct back to the logon. I want this to happen immediately.
logout link:
<h:form>
<h:panelGroup id="loginout">
<h:outputText value="#{todoController.loggedInUser}" />
<h:commandLink value="logout" action="#{todoController.logout}" />
</h:panelGroup>
</h:form>
logout code:
public String logout()
{
System.out.println("testing logout");
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
final HttpServletRequest r = (HttpServletRequest)ec.getRequest();
r.getSession( false ).invalidate();
return "../login.html?faces-redirect=true";
}
This can happen if the outcome is invalid. login.html doesn't seem to be a JSF page, so JSF navigation will simply fail.
You want to use ExternalContext#redirect() instead.
public void logout() throws IOException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ec.invalidateSession();
ec.redirect("../login.html");
}
Note that the above also demonstrates a more JSF-ish way to invalidate the session. Whenever you need to haul the raw javax.servlet.* API from under the JSF hoods, you should always ask yourself twice: "Is there really not a JSF-provided API for this?"
I have a page which takes in request params for place, then generate information,
for example, http://example.com/xxx/weather.jsf?place=california.
The purpose of doing this is to let user bookmark the link.
In the weather.jsf, there are two outputtext and a commandlink:
Humidity : <ice:outputText value="#{weatherBean.humidity}"/>
Visibility : <ice:outputText value="#{weatherBean.visibility}"/>
<ice:commandLink id="likeButton"
value="Like"
actionListener="#{weatherBean.doLike}" />
In the managedBean:
#ManagedBean(name="weatherBean")
#RequestScoped
public class WeatherBean
{
String humidity;
String visibility;
int numLike;
#PostConstruct
public void init()
{
System.out.println("init called");
HttpServletRequest request= (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
String place = request.getParameter("place");
setHumidity(WeatherDao.getHumidity(place));
setVisibility(WeatherDao.getVisibility(place));
setNumLike(GeneralDao.getNumLike());
}
public void doLike(ActionEvent event)
{
System.out.println("doLike called");
GeneralDao.addNumberLike();
}
}
Alright, the page generated perfectly.
However, when I click the doLike commandLink,
it always triggers the init method first, then call doLike method.
Since the request param is empty, all the other values reset.
Is there any way to prevent a refresh of the page or calling of init method?
I tried partialsubmit or immediate, but no luck.
Your bean is #RequestScoped, so after executing the JSF lifecycle, your bean instance is lost, until the next request comes in, at which point you get a new instance of your bean, and the PostContruct re-executes.
Try changing the scope of your bean to something longer lived, like #ViewScoped.