1

I'm having an issue with the back button, not keeping data in a dynamic dropdown in JSF on a request scoped bean.

I have a form with 2 dropdowns where dropdown2 is dynamic based on what is selected in dropdown1. Below is my code for these dropdowns.

<h:selectOneMenu id="group" label="group" value="#{queryBacking.groupInternalId}">
    <f:ajax event="valueChange" render="membership" />
    <f:selectItems value="#{supportBean.groupInstitutions}" var="group" itemValue="#{group.institutionInternalId}" itemLabel="#{group.institutionName}" />
</h:selectOneMenu>

<h:selectOneMenu id="membership" label="Membership" value="#{queryBacking.institutionInternalId}">
    <f:selectItem itemLabel="Select One" itemValue="0" />
    <f:selectItems value="#{queryBacking.groupMembershipInstitutions}" var="institution" itemValue="#{institution.institutionInternalId}" itemLabel="#{institution.institutionShortName}" />
</h:selectOneMenu>

My code works great except that if you submit the form and then click the back button, dropdown2 does not contain any values. How can fix this issue?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Catfish
  • 18,876
  • 54
  • 209
  • 353
  • change the scope to session or initialize the values on the page load with values from session – Luiggi Mendoza May 09 '12 at 16:29
  • I've tried changing the scope to session and that works, but the reason i don't like session scope is because if the user has 2 tabs open, the session scope messes up the data if they run new searches in tab 1, and then refresh tab 2. – Catfish May 09 '12 at 16:50
  • I know the problems changing from request to session scope, that's why I've also said you can initialize the values on the page with values from session. Also, what's the JSF version you're using? – Luiggi Mendoza May 09 '12 at 16:53
  • I'm not sure what you mean initialize the values on the page with values from session. Can you elaborate? I'm using JSF 2.0 – Catfish May 09 '12 at 16:57

2 Answers2

6

You mean the back button in the browser right?

The browser probably loads the page out of the browser cache. So you need to disable caching with a filter:

public class NoCacheFilter implements Filter {
    private FilterConfig config;

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpReq = (HttpServletRequest) request;
        HttpServletResponse httpRes = (HttpServletResponse) response;

        if (!httpReq.getRequestURI().startsWith(
                httpReq.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { 

            httpRes.setHeader("Cache-Control",
                    "no-cache, no-store, must-revalidate"); // HTTP 1.1.
            httpRes.setHeader("Pragma", "no-cache"); // HTTP 1.0.
            httpRes.setDateHeader("Expires", 0); // Proxies.
        }

        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        config = null;
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        this.config = config;
    }
}

And then add this to the web.xml:

<filter>
  <filter-name>NoCacheFilter</filter-name>
  <filter-class>yourpackage.NoCacheFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>NoCacheFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

You can specify the pages you want filtered in <url-pattern> </url-pattern>

tk2000
  • 631
  • 2
  • 6
  • 10
  • We had these tags in the meta statements, but they weren't being seen. Adding it to the response headers as described above in a filter made it work. Thanks! – Brenda Holloway Feb 29 '16 at 18:25
0

You can initialize the values for the page in the bean constructor:

TestBean class

@ManagedBean
@ViewScope
public class TestBean {
    private String name;

    public TestBean() {
        //initialize the name attribute

        //recover the value from session
        HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
            .getExternalContext().getSession(false);
        name = session.getAttribute("name");
        if (name == null) {
            name = "Luiggi";
        }
    }

    public String someAction() {
        //save the value in session
        HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
            .getExternalContext().getSession(false);
        session.setAttribute("name", name);
        return "Test";
    }

    //getters and setters...
}

Test.xhtml

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h:outputText value="Hello " />
        <h:outputText value="#{testBean.name}" />
        <h:form>
            <h:outputText value="Write your name: " />
            <h:inputText value="#{testBean.name}" />
            <br />
            <h:commandButton value="Change name" action="#{testBean.someAction}" />
        </h:form>
    </h:body>
</ui:composition>

Adding an example to remove the session attribute before navigating to Text.xhtml

SomeBean class

@ManagedBean
@RequestScope
public class SomeBean {
    public SomeBean() {
    }
    public String gotoTest() {
        //removes an item from session
        HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
            .getExternalContext().getSession(false);
        session.removeAttribute("name");
        return "Test";
    }
}

SomeBean.xhtml

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html">
    <h:body>
        <h:form>
            <!-- Every time you navigate through here, your "name" 
                 session attribute will be removed. When you hit the back
                 button to get Test.xhtml you will see the "name"
                 session attribute that is actually stored. -->
            <h:commandButton value="Go to Test" action="#{someBean.gotoTest}" />
        </h:form>
    </h:body>
</ui:composition>
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • This isn't working because since it's viewscoped so when you hit the search button, you go to a new view so the bean dies. When you hit the back button, the bean is recreated again. – Catfish May 09 '12 at 19:54
  • Wait, but just because the viewscoped bean dies, does that mean anything in the session from it dies as well or is that session data still kept around? – Catfish May 09 '12 at 19:55
  • Yes, the Request and View Scope are recreated when you hit the back button but the session is alive until it expires (check the web.xml for session-timeout) or the browser is closed (of course, no cookies are used in this example). – Luiggi Mendoza May 09 '12 at 19:58
  • Ok so this seems to work, but the issue i'm still having is that if you open another tab, the dropdown is populated with data form the session. – Catfish May 09 '12 at 20:58
  • You should check that your session variable must not exists before navigate/redirect to your page. – Luiggi Mendoza May 09 '12 at 21:01
  • Can you provide an example? I'm not sure how to do that and yet still have it work when hitting the back button. – Catfish May 09 '12 at 21:10
  • I don't think that works. Are you saying that i go from test.xhtml -> somebean.xhtml -> click button(which clears session)? In my situation, i have test.xhtml -> click submit(which clears session) -> takes you to somebean.xhtml, hit back button, session is cleared so it does not repopulate. – Catfish May 09 '12 at 21:25
  • No, its SomeBean -> Test -> AnotherPage then hit back button and Test.xhtml will have the session value(s). – Luiggi Mendoza May 09 '12 at 21:44