The @ViewScoped has been introduced by JSF 2.0 specification. In a nutshell the data which is @ViewScoped will keep living as long as you don’t navigate to another pagee to itself. The view scope is very convenient, since it allows the pattern of initializing data when you first access a page (via a non-faces request, which is typically a GET request) and then keep that data when you work on the page, doing postbacks, AJAX requests, etc.
JSF View best practice
This scope is quite useful when working with tables in JSF where you interact (add/edit/delete) with components in the table. Namely, in JSF there is a rule that the data that was used to render the table must be the EXACT SAME data that is used after the postback when processing the components you interacted with. With the view scope this is trivial, but without it it’s rather tricky.
In this example application we will show how to create a CRUD application based on @ViewScoped in as little as 1 page and 1 Backing Bean.
Create a New Dynamic Web Project, choosing the a Target Runtime which is compatible with JSF 2.0 (JBoss 6/7).
Next, select into the Project Facets to use JSF 2.0 Facets.
Now let’s add an index.html page which contains all the rendering logic:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:c="http://java.sun.com/jsp/jstl/core"> <h:head> <style type="text/css"> <!-- Omitted for brevity --> </style> </h:head> <h:body> <h2>View Scope</h2> <h:panelGroup rendered="#{empty viewManager.cacheList}"> <p>No data inserted yet.</p> </h:panelGroup> <h:panelGroup rendered="#{!viewManager.edit}"> <h3>Add Data</h3> <h:form> <p>Key: <h:inputText value="#{viewManager.item.key}" /> </p> <p>Value: <h:inputText value="#{viewManager.item.value}" /> </p> <p> <h:commandButton value="add" action="#{viewManager.add}" /> </p> </h:form> </h:panelGroup> <h:panelGroup rendered="#{viewManager.edit}"> <h3>Edit item #{viewManager.item.key}</h3> <h:form> <p>Key: <h:inputText value="#{viewManager.item.key}" /> </p> <p>Value: <h:inputText value="#{viewManager.item.value}" /> </p> <p> <h:commandButton value="save" action="#{viewManager.save}" /> </p> </h:form> </h:panelGroup> <h:form rendered="#{not empty viewManager.cacheList}"> <h:dataTable value="#{viewManager.cacheList}" var="item" styleClass="table" headerClass="table-header" rowClasses="table-odd-row,table-even-row"> <h:column> <f:facet name="header">Key</f:facet> <h:outputText value="#{item.key}" /> </h:column> <h:column> <f:facet name="header">Value</f:facet> <h:outputText value="#{item.value}" /> </h:column> <h:column> <h:commandButton value="edit" action="#{viewManager.edit(item)}" /> </h:column> <h:column> <h:commandButton value="delete" action="#{viewManager.delete(item)}" /> </h:column> </h:dataTable> </h:form> </h:body> </html>
The most interesting part is the method expression syntax:
<h:commandButton value="edit" action="#{viewManager.edit(item)}" />
This feature (requires an EL 2.2 capable container like JBoss 6/7) allows to pass parameter value in the method expression like this #{bean.method(param)}. This in turn allows to get rid of the DataModel object which acts as a glue between the JSF page and the Managed Bean.
Here is the ViewManager Bean which is annotated as @ViewScoped
package com.sample.bean; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.faces.bean.ManagedBean; import javax.faces.bean.ViewScoped; import com.sample.model.Property; @ManagedBean(name="viewManager") @ViewScoped public class ViewManager implements Serializable{ ArrayList<Property> cacheList = new ArrayList (); private Property item = new Property(); public ViewManager() { } private boolean edit; public void add() { cacheList.add(item); item = new Property(); } public void edit(Property item) { this.item = item; edit = true; } public void save() { item = new Property(); edit = false; } public void delete(Property item) { cacheList.remove(item); } public List getCacheList() { return cacheList; } public Property getItem() { return item; } public boolean isEdit() { return edit; } }