How to keep JSF flash scope parameters on page reload?
Asked Answered
D

1

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

Decerebrate answered 29/7, 2014 at 9:14 Comment(8)
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?Fumed
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?Fumed
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"Decerebrate
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.Fumed
@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 reloadDisplay
@Display 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...Fumed
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.Decerebrate
@Decerebrate - Another (dirtier) option would be stashing the variable in the ThreadLocal storageDisplay
F
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

Fumed answered 31/7, 2014 at 11:26 Comment(5)
Hi, do you know to get the persisted flash parameter value in managed bean?Countermeasure
@EvaMariam, see this answer.Fumed
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 ?Countermeasure
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 ?Assign
@KorayTugay, noo. You've got some documentation about this here. 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.<key>}, or to the request Map, to be promoted to the flash as if a call to put() or a set to the expression #{flash.<key>} was being called. . Seems to be an EL related feature.Fumed

© 2022 - 2024 — McMap. All rights reserved.