Pages

Saturday, January 01, 2011

JSF 2.x Component prerender() (PreRenderComponentEvent)

In Project Woodstock (Visual JSF), the page bean had a number of methods which could be overridden to provide additional functionality by adding convenient interception points in the JSF life cycle. This additional functionality was one of the selling points of Woodstock (Project Rave). If you are using JSF 1.2, it is still compelling.

One method which was very important was the prerender() method. This method was invoked prior to the page being rendered on the client. The com.sun.rave.web.ui.appbase.AbstractPageBean has a very complete explanation:



/**
* Callback method that is called just before rendering takes place.
* This method will only be called for the page that
* will actually be rendered (and not, for example, on a page that
* handled a postback and then navigated to a different page). Customize
* this method to allocate resources that will be required for rendering
* this page.
*/

This allowed for late binding of the component. This functionality has been added to JSF 2.0 in the SystemEvent facility. It is captured in two interfaces: PreRenderComponentEvent and PreRenderViewEvent. I will focus on the first interface, and provide an example for you.

This functionality is accomplished using the <f:event/> tag.  In this series of examples we have an <h:outputText/> which has its value injected displaying the event which was called, and a second more useful example which pre-populates <f:selectItems/> for use in an <h:selectOneListbox/> which also includes <f:ajax/> to display the selected value.


event.xhtml



<?xml version="1.0" encoding="UTF-8"?>
<!--
 Copyright 2010 Blue Lotus Software, LLC.
 Copyright 2010 John Yeary <jyeary@bluelotussoftware.com>.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 under the License.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>&lt;f;event/&gt;</title>
    </h:head>
    <h:body>
        <h:form id="form1">
            <h:panelGrid id="panelGrid1" columns="1">
                <h:outputText id="outputText1">
                    <f:event id="event1" type="javax.faces.event.PreRenderComponentEvent" listener="#{eventBean.preRenderComponent}"/>
                </h:outputText>
                <h:selectOneListbox id="selectOneListbox" value="#{eventBean.selectedItem}">
                    <f:event id="event2" type="javax.faces.event.PreRenderComponentEvent" listener="#{eventBean.updateSelectItems}"/>
                    <f:ajax id="ajax1" render="outputText2"/>
                </h:selectOneListbox>
                <h:outputText id="outputText2" value="#{eventBean.selection}"/>
            </h:panelGrid>
        </h:form>
    </h:body>
</html>


EventBean.java



/*
 *  Copyright 2010 Blue Lotus Software, LLC.
 *  Copyright 2010 John Yeary <jyeary@bluelotussoftware.com>.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
/*
 * $Id:$
 */
package com.bluelotussoftware.example.jsf;

import java.util.ArrayList;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UIOutput;
import javax.faces.component.UISelectItems;
import javax.faces.component.UISelectOne;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.model.SelectItem;

/**
 * This is the {@link javax.faces.bean.ManagedBean} for the {@literal event.xhtml}
 * page. It is provided to demonstrate the {@literal <f:event/>} tag and its usage
 * in handling {@link javax.faces.event.PreRenderComponentEvent} events to populate
 * the representative components with values.
 * 
 * @author John Yeary <jyeary@bluelotussoftware.com>
 * @version 1.0
 */
@ManagedBean
@RequestScoped
public class EventBean {

    /**
     * value holder for the selected {@link javax.faces.component.html.HtmlSelectOneListbox}.
     */
    private String selectedItem;

    /**
     * Default constructor.
     */
    public EventBean() {
    }

    /**
     * Getter for the selected {@link javax.faces.component.html.HtmlSelectOneListbox}.
     * @return selected value.
     */
    public String getSelectedItem() {
        return selectedItem;
    }

    /**
     * Setter for the selected {@link javax.faces.component.html.HtmlSelectOneListbox}.
     * @param selectedItem set the component value.
     */
    public void setSelectedItem(String selectedItem) {
        this.selectedItem = selectedItem;
    }

    /**
     * Event Handler for {@link javax.faces.event.ComponentSystemEvent}. The usage here captures
     * the higher level event, but we are using it to capture {@link javax.faces.event.PreRenderComponentEvent}
     * and set the appropriate values.
     * @param event triggering component event to handle.
     */
    public void preRenderComponent(ComponentSystemEvent event) {
        UIOutput output = (UIOutput) event.getComponent();
        output.setValue(event.getClass().getName() + " fired.");
    }

    /**
     * Event Handler for {@link javax.faces.event.ComponentSystemEvent}. This method
     * sets the {@link javax.faces.component.UISelectItems} prior to the component being
     * rendered.
     * @param event triggering component event to handle.
     */
    public void updateSelectItems(ComponentSystemEvent event) {
        ArrayList<SelectItem> items = new ArrayList<SelectItem>();
        items.add(new SelectItem("Tuna", "Tuna"));
        items.add(new SelectItem("Salmon", "Salmon"));
        items.add(new SelectItem("Mojarra", "Mojarra", "A delicious fish, and UI framework."));
        items.add(new SelectItem("Tilapia", "Tilapia", null, true));
        UISelectItems selectItems = new UISelectItems();
        selectItems.setId("selectItems1");
        selectItems.setValue(items);

        UISelectOne uISelectOne = (UISelectOne) event.getComponent();
        uISelectOne.getChildren().add(selectItems);
    }

    /**
     * Returns the selected value.
     * @return selected value.
     */
    public String getSelection() {
        if (selectedItem != null) {
            return selectedItem;
        }
        return "Nothing Selected";
    }
}
}

Here is the result:


2 comments:

  1. Perfecto!! justo lo que necesitaba. Yo lo utilicé para preseleccionar un campo, aún cuando no se mostrara. Muchas gracias!!

    ReplyDelete
  2. Thanks for this,.. it helped me a lot!!

    ReplyDelete