Search code examples
jsf-2richfacesfacelets

jsf 2.0 @ViewScoped redirect (navigation) to target="_blank"


Basically the same question as here

How do I retain a ViewScoped bean on the page from which I redirect to a different browser tab:

firstPage.xhtml:

<h:commandLink action="#{controller.redirect}" value="#{bean.value} target="_blank"/>

When redirect/navigation finishes with initializing the other beans, it destroys this #{bean} in the process. In the redirected code I am not even using #{bean}. This used to work with

<a4j:keepAlive>

Here's my current setup. bean class:

@ViewScoped
public class Bean{ 
    @PreDestroy
    public void onDestroy(){ // being destroyed when I don't want to }
}

faces-config:

<navigation-rule>
  <from-view-id>/firstPage.xhtml</from-view-id>
    <navigation-case>
      <from-outcome>redirect</from-outcome>
      <to-view-id>/secondPage.xhtml</to-view-id>
  </navigation-case>
</navigation-rule>

Solution

  • You need to do as Luiggi suggested and store data temporarily in the session or pass the data (or keys sufficient to re-fetch the data) via query parameters to the target view. This is the case even if you weren’t redirecting and/or targeting a new window/tab.

    View scope is strange. It exists only as long as the user stays on the same view. When JSF sees that the view has been navigated away from, it will automatically destroy any beans scoped to that view.

    There are two ways that you can navigate to a different view. The first is a non-faces request, such as from h:link or h:button. In this case, the previous view is not being restored so JSF wouldn't know that there are any view-scoped beans to destroy. The second is a faces request, such as from h:commandLink or h:commandButton, that returns something other than void or null. In this case, there is a postback to the view, which is restored in order to process the action. If the result of that action is to navigate away from that view, redirect or not, any beans scoped to that view will be destroyed.

    Under the hood, view scope is essentially session scope with some built-in semantics for cleaning up “old” data. This actually works well if users don’t open the application in more than one window/tab and only use navigation provided within the application (i.e., not the browser back/forward buttons). However, since we’re talking about targeting web browsers, view scope is, in my opinion, pretty useless (with the only exception being cases where you can control the target browser and completely disable back/forward/reload/location, but it doesn’t sound like you’re in that kind of environment).