9

I use flash scope to pass a setting object between @viewscoped contollers. But if I make a page reload on one of them, then the flash map is empty and the setting object is not initialized. Is it possible to keep flash scope on page reload?

My source code to store/retrieve settings:

FistPage.xhtml

...
<p:commandButton value="next"
    action="#{firstPageController.transferConfig}"  
    process="@this" />
...

FirstPageController.java

@ManagedBean(name = "firstPageController")
@ViewScoped
public class FirstPageController {
...
public String transferConfig() {
FacesContext.getCurrentInstance().getExternalContext().getFlash().put("searchConfig",   searchConfig);
return "/secondPage.xhtml?faces-redirect=true";
}
...
}

SecondPage.xhtml

...
<h:outputLabel value="value">
    <f:event type="preRenderComponent" listener="#{secondPageController.onPageLoad()}"/>
</h:outputLabel>
...

SecondPageController.java

@ManagedBean(name = "secondPageController")
@ViewScoped
public class SecondPageController {
    ...
    public void onPageLoad() 
    {
        flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();

        searchConfig = ((SearchFilterConfig) flash.get("searchConfig"));

        flash.putNow("searchConfig", searchConfig);

        flash.keep("searchConfig");
    }
    ...
}

I use Mojarra 2.1.29

Thanks

Alex
  • 111
  • 1
  • 1
  • 3
  • Where are you invoking this method from? This will do nothing if the parameter isn't already in the map... Are you recording it anywhere else? – Aritz Jul 29 '14 at 11:13
  • I just realized you're not performing a redirection at all for going to your second view. Can you see the url in the address bar changed? – Aritz Jul 29 '14 at 12:29
  • Yes, I can. I changed it in the code above. The problem occurre only if I reload the secondPage or perform action on the secondPage with update="@all" – Alex Jul 29 '14 at 12:39
  • They are different things. First one is a `GET` request for the view, the second one you talk about is a postback over the same view. Second one could be avoided either keeping the flash param or storing it in `@ViewScoped`. – Aritz Jul 29 '14 at 12:59
  • 1
    @Alex: what's the point of using the flash scope for a same-page reload of a `@ViewScoped` bean? You could just store the variable as an instance variable of that bean and it'll still be there on reload – kolossus Jul 29 '14 at 13:02
  • @kolossus I think when he talks about page reloading he's talking about GETting the page again, manually. The state of the bean won't be preserved then, as the `@ViewScoped` only works for postbacks over the same view... – Aritz Jul 29 '14 at 13:15
  • I mean a GET request (F5 f.e.). I also have the language button on the page, if I press that the whole view will be updated, but I'd like to keep the state/config. The problem is the view can be perform from other parts of application and get different configs. So I can not use the session scope. – Alex Jul 29 '14 at 13:31
  • @Alex - Another (dirtier) option would be stashing the variable in the ThreadLocal storage – kolossus Jul 29 '14 at 14:26

1 Answers1

8

I just did some tests in my playground project and realized it's actually possible to keep the state of the flash parameters even if you GET the page again, using {flash.keep}. That's how the JSF docs explain it:

The implementation must ensure the proper behaviour of the flash is preserved even in the case of a <navigation-case> that contains a <redirect />. The implementation must ensure the proper behavior of the flash is preserved even in the case of adjacent GET requests on the same session. This allows Faces applications to fully utilize the Post/Redirect/Get design pattern.

Here you've got a nice basic test case:

page1.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head />
<h:body>
    <h:form>
        <h:button id="nextButton" value="Next (button)" outcome="page2.xhtml" />
        <c:set target="#{flash}" property="foo" value="bar" />
    </h:form>
</h:body>
</html>

page2.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html">
<head />
<body>foo = #{flash.keep.foo}
</body>
</html>

Just open the first page and click on the button which will redirect you to the second one. Then refresh the second page as many times as you want and you'll find the parameter persisting.


Tested in Mojarra 2.2.6

Aritz
  • 30,971
  • 16
  • 136
  • 217
  • Hi, do you know to get the persisted flash parameter value in managed bean? – mehere Sep 30 '15 at 12:36
  • @EvaMariam, see [this answer](http://stackoverflow.com/questions/11194112/understand-flash-scope-in-jsf2/21277621#21277621). – Aritz Sep 30 '15 at 13:37
  • i dont want to display the flash parameter in front end (ui). it should be reused in the bean on manual reload, to get other values from db. can you take a look at [this](http://stackoverflow.com/questions/32864459/can-the-flash-data-be-persisted-after-redirection) ? – mehere Oct 01 '15 at 06:38
  • What kind of dark magic is going on in here? keep is a method with no return type and accepts a String as parameter but you are calling it with no parameter and chaining it with .foo ? – Koray Tugay Jun 24 '16 at 19:25
  • @KorayTugay, noo. You've got some documentation about this [here](http://docs.oracle.com/javaee/7/api/javax/faces/context/Flash.html#keep-java.lang.String-). More or less: `Parameters: key - if argument key is the name of an entry previously stored to the flash on this traversal through the lifecycle via a call to putNow(java.lang.String, java.lang.Object), or to a set to the EL expression #{flash.now.}, or to the request Map, to be promoted to the flash as if a call to put() or a set to the expression #{flash.} was being called.` . Seems to be an EL related feature. – Aritz Jul 11 '17 at 18:55