The view scope

The view scope lives as long as you are navigating in the same JSF view in the browser window/tab.

The view scope is useful when you need to preserve data over multiple requests without leaving the current JSF view by clicking on a link, returning a different action outcome, or any other interaction that dumps the current view. It gets created upon an HTTP request and gets destroyed when you postback to a different view; as long as you postback to the same view, the view scope is alive.

Note

Notice that the view scope bean might get passivated by the container and should be capable of passivity by implementing the java.io.Serializable interface.

Since the view scope is particularly useful when you are editing some objects while staying in the same view, it can be the perfect choice for rich AJAX requests. Moreover, since the view scope is bounded to the current view, it does not reflect the stored information in another window or tab of a browser; this is an issue specific to the session scope!

Note

In order to keep the view active, the bean methods (actions/listeners) must return null or void.

The view scope is not available in CDI, but JSF 2.2 has introduced it through the new annotation, @ViewScoped. This is defined in the javax.faces.view.ViewScoped package and it is compatible with CDI. Do not confuse this @ViewScoped with the one defined in the javax.faces.bean package, which is JSF compatible!

Note

The view scope annotation is @ViewScoped and is defined in the javax.faces.view package for CDI, and in the javax.faces.bean package for JSF.

You can see the view scope in action by modifying the PlayersBean scope as follows:

import java.io.Serializable;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class PlayersBean implements Serializable{
  ...
}

Firing multiple HTTP requests by clicking on the button labeled Get Players In Same View will reveal something like the following screenshot. Notice the action method (newPlayer) returns void and the button doesn't contain the action attribute, which means that you are in the same JSF view during the execution of these requests.

The other two buttons contain the action attribute and indicate an explicit navigation, which means that the current view is changed at every request and the data is lost.

You can easily adapt PlayersBean (and any other bean) to use the JSF version of @ViewScoped as follows:

import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean
@ViewScoped
public class PlayersBean implements Serializable{
  ...
}

Data submitted through forms across the view scope will be available in subsequent requests as long as you are in the same view.

Note

A method annotated with @PostConstruct will be called only when the view scoped bean is instantiated. Subsequent requests, from this view, will use this instance. As long as you are in the same view, this method will not be called again; therefore, it can be a good place to add initialization stuff specific to the current view.

The case of the CDI bean is wrapped into the application named ch3_6_1, while the case of the JSF bean is wrapped into the application named ch3_6_2.

Note

Starting with JSF 2.2, we can use the UIViewRoot.restoreViewScopeState(FacesContext context, Object state) method for restoring the view scope when it is not available. This will be exemplified in Chapter 12, Facelets Templating.