View scope in RichFaces

If you have been using JSF for a while, you know that in some instances, request scope is too short and session scope is too long to store objects. This of course applies to a situation where you need to keep some data for longer than a request but less than session. If you use Seam or Spring, then you get conversation and view scopes which solve this problem. JSF 2.0 also comes with view scope. If you are using JSF 1.2 with just managed beans, and at this point I’m guessing that’s basically everyone (meaning you are not using JSF 2 yet), then you are kind of stuck.

Luckily RichFaces comes with a view scope. View scope means you can keep the object alive as long as you are staying on the view (page). The bean is saved as an attribute of the JSF view. When the JSF view (its state) is saved, the bean is saved as well. When the view is restored, the bean is restored and placed back in request scope.

There are two ways place a bean in view scope. One is using a4j:keepAlive tag, second is to use @KeepAlive annotation. Let’s see how both are used. Our one page application is a list of any random words. Words can added and deleted (more screen shots at the end).

screenshot82

Bean:

package example;
 
import java.util.ArrayList;
import javax.annotation.PostConstruct;
 
public class Bean {
   private ArrayList <String> words;
   private String selectedWord;
   private String newWord;
 
   public void delete (){
	words.remove(selectedWord);
   }
   public void add (){
	words.add(newWord);
   }
   @PostConstruct
   public void create () {
	words = new ArrayList <String>();
	words.add("Hello");
	words.add("World");
	words.add("Peace");
	words.add("Soccer");
	words.add("JSF");    
   }
   public String getNewWord() {
	return newWord;
   }
   public void setNewWord(String newWord) {
	this.newWord = newWord;
   }
   public ArrayList<String> getWords() {
	return words;
   }
   public void setSelectedWord(String selectedWord) {
	this.selectedWord = selectedWord;
   }
}

Registering the bean, placing it in request scope:

<managed-bean>
  <managed-bean-name>bean</managed-bean-name>
  <managed-bean-class>example.Bean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
 </managed-bean>

JSF page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h:form>
   <a4j:keepAlive beanName="bean" />
   <h:panelGrid columns="2">
	<h:inputText value="#{bean.newWord}" size="8" />
	<a4j:commandButton action="#{bean.add}" value="Add" reRender="table" />
   </h:panelGrid>
   <rich:dataTable id="table" value="#{bean.words}" var="_word">
       <h:column>
	   <a4j:commandLink action="#{bean.delete}" value="Delete" 
                  reRender="table">
		<f:setPropertyActionListener value="#{_word}"
			target="#{bean.selectedWord}" />
	   </a4j:commandLink>
	</h:column>
	<h:column>
		<h:outputText value="#{_word}" />
	</h:column>
   </rich:dataTable>
</h:form>

On line 2, a4j:keepAlive tag points to managed bean name that will be saved with the view thus giving us view scope. When this page is restored (as a result of add or delete action), bean managed bean will be re-created and placed in request scope. Without the view scope, after any action add or delete we would always see the original list of values as the bean would be re-created on each request.

Instead of using a4j:keepAlive tag, we can also use @org.ajax4jsf.model.KeepAlive annotation:

package example;
 
import java.util.ArrayList;
import javax.annotation.PostConstruct;
 
@org.ajax4jsf.model.KeepAlive
public class Bean {
   private ArrayList <String> words;
   private String selectedWord;
   private String newWord;
 
   // rest of code...
}

Lastly, a4j:keepAlive tag comes with just one attribute:

<a4j:keepAlive beanName="bean" ajaxOnly="true"/>

When set to true, bean value is restored for AJAX requests only.

Screen shots

Running for the first time:
screenshot82

After entering ‘Flowers’ and clicking Add:
screenshot83

After deleting ‘JSF’:
screenshot84

24 comments

  1. Pingback: View scope in Richfaces « JSF Recipes – Organizing your Kitchen
  2. tizero

    Hi max, is such a view scope also useful for a small pageflow of 2-3 pages (the 2-3 pages all use the same bean)?

  3. max

    View scope only works if you stay on the same page. If you need to navigate, you can navigate within a4j:include this way it’s still the same page (the parent of a4j:include).

  4. James

    Hi Max, I tried this ajax demo on Tomcat 6 with Netbeans 6.7, the page displayed fine that you can see the input text, the “add” button and the datatable. When I clicked the Add button, it caused the following page error in IE8, the datatable was not rerendered.

    Webpage error details

    User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; FunWebProducts; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
    Timestamp: Thu, 16 Jul 2009 15:47:07 UTC

    Message: Object required
    Line: 200
    Char: 362
    Code: 0
    URI: http://localhost:6080/RichFacesClient/a4j/g/3_3_1.GAorg.ajax4jsf.javascript.AjaxScript.jsf

  5. feng

    hi Max, nice job! Thank you very much for this article.

    A question about “If you use Seam or Spring, then you get conversation and view scopes which solve this problem”. My web application uses spring2.5 (under tomcat 6), and it’s based on your example “richfaces-spring-wizard.zip”.

    Now when I put

    @Component(“bean”)
    @Scope(“view”)

    before a class name, it doesn’t work. It gives errers :

    java.lang.IllegalStateException: No Scope registered for scope ‘view’

    Do you know, by any chance, how to make a custom scope such as “view” with Spring? (an example will be great)

    Thank you in advance,

    Feng @ Paris

  6. James

    Here is the .xhtml for you demo. I replaced with . a4j:log shows
    debug[12:46:39,893]: Have Event [object Object] with properties: target: [object HTMLInputElement], srcElement: [object HTMLInputElement], type: click
    debug[12:46:39,893]: Query preparation for form ‘null’ requested. Any idea?

    ————————————————————————

  7. James

    Hi Max, I figured it out why it was not working. My .xhtml was not right. It’s working now. Thanks for the nice post.

  8. James

    Just curious, can you post a simple example about drag and drop between trees?

    By the way, the book is great.

    Thanks.

  9. Pingback: Learning JSF2: Managed beans | Maxa Blog
  10. sachin

    max,

    I have actually posted this question in another site regarding extendeddatatable.

    My requirement is I have several tabs and one of the tabs uses rich:extendedDataTable. If sortby is clicked in the page where table is used and if I navigate to another page, it looks for the bean of the old page and throws an error saying that sortyBy of the column is undefined.

    For eg if iused sortBy on userId in tab1( where the table column must have had sortBy=#{data.userId}) and then i click on tab2 , it looks for the data.userId and thorws an error. I am using richfaces 3.2.2SR1 version.

    can you help me on this.

  11. sachin

    complete stack trace
    javax.el.PropertyNotFoundException: /amendapplication/historyDetails.xhtml @33,174 sortBy=”#{data.statusChangeTime}”: Property ‘statusChangeTime’ not found on type uk.gov.wales.rpd.domain.applicationmanagement.ApplicationAttributeEntity
    com.sun.facelets.el.TagValueExpression.getValue(TagValueExpression.java:73)
    org.richfaces.model.impl.expressive.ValueBindingExpression.evaluate(ValueBindingExpression.java:59)
    org.richfaces.model.impl.expressive.ObjectWrapperFactory.wrapObject(ObjectWrapperFactory.java:189)
    org.richfaces.model.ModifiableModel$RowKeyWrapperFactory.wrapObject(ModifiableModel.java:57)
    org.richfaces.model.impl.expressive.ObjectWrapperFactory$2.convert(ObjectWrapperFactory.java:177)
    org.richfaces.model.impl.expressive.ObjectWrapperFactory.convertList(ObjectWrapperFactory.java:138)
    org.richfaces.model.impl.expressive.ObjectWrapperFactory.wrapList(ObjectWrapperFactory.java:175)
    org.richfaces.model.ModifiableModel.sort(ModifiableModel.java:235)
    org.richfaces.model.ModifiableModel.modify(ModifiableModel.java:206)
    org.richfaces.component.UIExtendedDataTable.createDataModel(UIExtendedDataTable.java:310)
    org.ajax4jsf.component.UIDataAdaptor.getExtendedDataModel(UIDataAdaptor.java:621)
    org.ajax4jsf.component.UIDataAdaptor.setRowKey(UIDataAdaptor.java:339)
    org.ajax4jsf.component.UIDataAdaptor.iterate(UIDataAdaptor.java:1034)
    org.ajax4jsf.component.UIDataAdaptor.processDecodes(UIDataAdaptor.java:1158)
    org.ajax4jsf.component.UIDataAdaptor.processDecodes(UIDataAdaptor.java:1168)
    javax.faces.component.UIForm.processDecodes(UIForm.java:209)
    org.ajax4jsf.component.AjaxViewRoot$1.invokeContextCallback(AjaxViewRoot.java:392)
    org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:238)
    org.ajax4jsf.component.AjaxViewRoot.processDecodes(AjaxViewRoot.java:409)
    com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:78)
    com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
    com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    javax.faces.webapp.FacesServlet.service(FacesServlet.java:265)
    org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:341)
    org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:177)
    org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:267)
    org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:380)
    org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:507)
    org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)

  12. Pingback: Learn how to add/delete table row with RichFaces [in 5 minutes] | Maxa Blog
  13. Trackback: Confluence: UI Team
  14. Pingback: View scope in RichFaces « Onur's Realm
  15. leonardo

    hi max btw i’m leo i would like to asking about keepAlive tag
    but i have a problem how do i remove keepAlive session in my bean

  16. leonardo

    hi max btw i’m leo i would like to asking about keepAlive tag
    but i have a problem how do i remove keepAlive session in my bea

  17. Pingback: View Scope in JSF 1.2 using RichFaces « AboSabry

Leave a Reply