Learning JSF2: Page params and page actions

Learning JSF 2 series continues with page parameters and page actions. Read other Learning JSF 2 articles.

If you worked with JSF 1.2, you know that calling a page action wasn’t simple. A page action is useful when you request a page for the first time (GET request) and would like to prepare some data to be rendered on a view (page). Of course there are some workarounds, one of them is to use @PostConstruct method inside the bean or even create a phase listener. Both could work but developers desired a more robust, and out of the box solution similar to what Seam 2 provides.

A feature that closely relates to page action is page params (page parameters). Usually when you issue a get request like this:


http://host/app/page.jsf?productId=101

you want the productId request parameter to be assigned to a property inside a bean so that you can use the id inside action (page action) to load data to display on the page. In JSF 1.2, you would end up doing something like this:

Managed bean:

@ManagedBean(name="bean")
public class Bean {
   private Integer productId;  // getter and setter
}

JSF configuration file:


  bean
  test.Bean
  request
  
   productId
   #{param['productId']}
  

#{param} is an implicit object in JSF that holds all request parameters. In the code snippet above, we are taking the value of productId and assigning it to productId property inside the bean using JSF managed bean facility. It’s just not an elegant solution and it doesn’t offer any flexibility, ability to validate the value, and also defined separately from the actual page.

The good news is that both page actions and page params are supported by JSF 2. Let’s start with page params.

Page params

We all know that when we have a JSF input field bound to a bean property and we submit the page ( POST), the value entered in the page automatically get pushed into the bean (assuming no conversion/validation errors or anything else stopping the life cycle).

JSF page:


Bean:

public class Bean {
   private Integer productId;  // getter and setter
}

The easiest way to think of page params is that the same thing is happening as above but only without input fields on the page. Instead, the values are submitted via the GET URL and pushed in the same way into the bean:


http://host/app/page.jsf?productId=101

In both cases the result is the same, the value either from the page or URL is set into the property. We know how to do it with input field bound to a property during a POST. Let’s see what needs to be done when a GET request is issued. We have to somehow map the request param to bean properties.

JSF 2 introduced a new metadata tag called inside which pages params are defined:







  
  



  ...


In the code example above tag contains two new tags in JSF 2. As you guessed, the tag defines and maps two page params to bean properties. In the first one, productId param is mapped to bean.productId property. The second param text is mapped to bean.text bean property. The following GET request will take productId value of 101 and text value of ‘nice’ and set them into their respective bean properties:


http://localhost:port/app/page.jsf?productId=111&text=nice

A quick and easy way to test that values were set into the proprieties is just to render the values on the page:



Default values

If bean properties are set to some initial values page params will overwrite them (same as with a POST). If page params are not provided then during rendering the default values will be displayed.

Good to know

The tag is actually an alias for a special view level facet in JSF 2:


   

As this metadata tag going to be used extensively, a shortcut tag (alias) was created:


   

The tag is actually not required. As we are using Facelets (default in JSF 2), the entire page is a view by default.

Conversation and validation

When a value is submitted via a POST it can bean converted and validated before being pushed into the bean property. For a GET request, conversation and validation can be invoked in a similar fashion. When either fails, error message can be displayed just like with a POST.

When components are bound to a bean property, a converted or validator is registered with the component on the page. As we don’t have a component, conversation and validation is added to the tag.

Requiring a value

To make a value required, we use the familiar required attribute and overwrite the default error message:


   
   

To display the error message, is added to the page:




Note: we have to use as the message is not associated with any component.

For example, the following request:


http://localhost:port/app/page.jsf?productId=111&text=

will produce the following:

As we didn’t provide a value for text, validation fails. productId is also not set as Update Model phase was not executed (as expected after validation fails).

Good to know

When a page (view) is requested via a GET and no page params are present, Restore View and Render Respose phases will be executed (same behavior you get in JSF 1.2). Once page params are added to a GET request, JSF will run through the full life cycle in order to convert and validate the values and then set the values into the bean.

More validation

In addition to requiring a value, we can attach other standard validators to page params such as range validator for numbers and length validator for strings. For example:


   
	    
   
   
                
    

In this example, was added to productId param and to text param. For both custom validation error message was set.

For example the request with the parameters which not meets the requirements specified will produce the following:

Lastly, a custom validator can be attached as well via validator attribute (in which case the method is validation method is placed inside the bean):


or with tag (in which case a class is defined which implements the Validator interface):


   

Conversion

As with validation, conversation is added in similar fashion. When we do a POST, all values are first converted and then validated. All values entered on a page are sent as strings and need to be converted before pushed into bean properties. Page param values are also sent as plain strings. Taking the productId param, a converter could be added like this:


     

This is just to demonstrate how it’s done but we don’t actually have to register the integer converter. Integer converter is one of the default converters in JSF which means that JSF will try to convert the value automatically. The converter attribute could be used to attached a custom converter as well.

Page actions

Page actions can be used to initialize data to be rendered in the view. Page actions are added with new the tag inside view metadata.


   
   
   

Two things are specified above, the event type (preRenderView) and the action listener to be invoked. The preRenderView event type indicates that this listener will be invoked during Render Respone phase.

Just for demonstration purposes, let’s use the productId value as a counter for the number of times to insert text value into a list and then display it.

Bean:

public ArrayList list; // getter

public void loadAction() {
    list = new ArrayList();
    for (int i = 0; i < productId ; i++) {
	list.add(text);
    }
}

For this to work, page params need to be set first and that’s exactly what happens. Page params are set into the model during Update Model phase and page action is invoked during Render Response phase (just before the rendering). We use a page param (productId) to decide how many times to insert the text value into the list. To render the list, we use this:

  1. #{txt}

Entering the following URL:


http://host:port/app/page.jsf?productId=5&text=JSF2

will produce the following:

Note that if conversation or validation fails, the listener (page action) is still invoked. However, an exception will be thrown as productId is null (unless it’s initialized to some value). One option is to check if any error messages were queued and skip the listener logic. For example:

public void loadAction() {
   List messages = FacesContext.getCurrentInstance()
	.getMessageList();

   if (messages.size() == 0) {
	list = new ArrayList();
	for (int i = 0; i < productId ; i++) {
		list.add(text);
	}
   }
}

Note: if only page action is present without page params, then only Restore View and Render Response phase are executed.

Summary

Page params and page actions are two great features in JSF 2. Being able to issue a GET with request params also allows to create bookmarkable URLs. Bookmarkable URLs and how page params are tied to navigation as well as the new and tags will be covered in the next article in this series.

27 thoughts on “Learning JSF2: Page params and page actions

  1. Hi Max!
    Thank you very much for this great introduction to the prospects of page params.
    I’m wondering if this page params also return “url-params” that are passed after a hash (#) in an URL (http://localhost:port/app/page.jsf#productId=111,text=nice)? This would have the big advantage that params dynamically inserted after the hash in an URL do not cause a full page refresh, which would be a precondition to support bookmarkable URLs on AJAX pages (i.e. pages where only parts are replaced with AJAX requests).
    If not, I’m looking forward to your next article covering bookmarkable URLs – I hope AJAX request are covered there.

  2. Hi Max,
    thank you very much for your quick response!
    Yesterday I incidentally came across the rich:hashParam component on your blog about the components yet available in RichFaces4. Unfortunately I didn’t find any description for this component (apart from “Incomplete” in the RichFaces doku @ JBoss.org). With this component, is it possible to get URL parameters that are passed after an #? E.g. the param “productId” in an URL like http://localhost:port/app/page.jsf#productId=111. Does rich:hashParam work similarly to f:viewParam?
    Thank you yery much in advance!
    PS: With “I hope AJAX requests are covered there” in my last post I meant the bookmarkability of pages where parts of the page are dynamically changed by AJAX request. I.e. how to bookmark a site when there’s never a full page refresh (a GET request where the URL changes) but just AJAX requests changing parts of the site.

  3. @Smax: rich:hashParam creates a JavaScript param (hash) that can be used together with rich:componentControl to pass params to the component you are controlling.

  4. Ok It’s useful, but what happend with particular characters like ñ (Spanish letter)?

    If you have in the text param a word like España instead of JSF2, you will have problems, because the browser will translate in something like ñ and I don’t know if it’s possible to decode. :(

  5. Just as a correction to your post, when using a custom validator, the attribute is validatorId, not validator.

    <f:validator validatorId=”produdIdValidator” />

    Thanks for the great post though!

  6. Is it possible to combine the metadata/viewparam tags with the templating mechanism (I have a template and need the viewparams on each page)? I tried to implement it that way, unfortunately the values are not set in the managed bean.

  7. @Mike: I can’t be 100% sure but I’d think it’s possible. Template or not template.. at the end you just get a complete, single page (so the template shouldn’t matter).

  8. Hi!

    I wonder if it’s possible to redirect the user if he’s supplied invalid params or in case of an error in the page action! We need this kind of functionality but don’t know what the best practice for this is in JSF.

    Any thoughts?
    Thanks!

  9. Thanks for this article, Max. It is very informative. Glad to see you are still responding to replies a year and half later!

    If I enter the url

    http://localhost:8080/contacts-as7/index.jsf?sitecode=0200

    I get exactly the result I want. I use f:viewParam to set the sitecode and f:event to retrieve the site info:

    Here’s where I am having trouble. In addition to being able to jump right into the page with a URL containing a parameter, I also want to be able to enter a sitecode into an input field on the same page and end up with the same result, ie parameter in the URL and correct info on the page.

    It seems I can do either the GET using f:viewParam and f:event (no input field) or the POST using h:commandButton (no parameter in the URL).

    How do I make my app do both?

  10. Thanks for pointing me in the right direction. I did the POST and the return string from the POST action included the parameter in the URL together with faces-redirect=true

    return “index.jsf?sitecode=” siteCode “&faces-redirect=true”;

    the xhtml file included the metadata to make use of the redirected URL

    f:viewParam name="sitecode" value="#{contactView.siteCode}" /f:viewParam
    f:event listener="#{contactView.retrieve}" type="preRenderView"/f:event
    

    TDR

  11. Max, do you know if there is some issues with param and c:forEach?

    I am creating a pagination bar, using c:forEach to create the page numbers as h:links with param. Other h:links are a working, setting the value in the managedbean property, but that inside the c:forEach not.

      • Changed to ui:repeat and no success… restarted all enviroment, including Web”cache”Sphere, now it works very well. It seems like a cache problem with the server. Thank you, Max.

  12. Hey there! Quick question that’s completely off topic.
    Do you know how to make your site mobile friendly?
    My weblog looks weird when viewing from my iphone.
    I’m trying to find a theme or plugin that
    might be able to resolve this problem. If you have any recommendations,
    please share. Many thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s