7 Rerendering Partial Page Content

This chapter describes how to use the partial page render features provided with ADF Faces components to rerender areas of a page without rerendering the whole page.

This chapter includes the following sections:

7.1 Introduction to Partial Page Rendering

AJAX (Asynchronous JavaScript and XML) is a web development technique for creating interactive web applications, where web pages appear more responsive by exchanging small amounts of data with the server behind the scenes, without the whole web page being rerendered. The effect is to improve a web page's interactivity, speed, and usability.

With ADF Faces, the feature that delivers the AJAX partial page render behavior is called partial page rendering (PPR). PPR allows certain components on a page to be rerendered without the need to rerender the entire page. For example, an output component can display what a user has chosen or entered in an input component, or a command link or button can cause another component on the page to be rerendered, without the whole page rerendering.

In order for PPR to work, boundaries must be set on the page that allow the lifecycle to run just on components within the boundary. In order to determine the boundary, the framework must be notified of the root component to process. The root component can be identified in two ways:

  • Events: Certain events indicate a component as a root. For example, the disclosure event sent when expanding or collapsing a showDetail component (see Section 8.9, "Displaying and Hiding Contents Dynamically"), indicates that the showDetail component is a root. When the showDetail component is expanded or collapsed, only that component goes through the lifecycle. Other examples of events identifying a root component are the disclosure event when expanding nodes on a tree, or the sort event on a table.

  • Components: Certain components are recognized as a boundary, and therefore a root component. For example, the framework knows a popup dialog is a boundary. No matter what event is triggered inside a dialog, the lifecycle does not run on components outside the dialog. It runs only on the popup.

In addition to built-in PPR functionality, you can configure components to use cross-component rendering, which allows you to set up dependencies so that one component acts as a trigger and another as the listener. When an event occurs on the trigger component, the lifecycle is run only on listener components and child components to the listener, and only the listener components and their children are rerendered. Cross-component rendering can be implemented declaratively. However, by default, all events from a trigger component will cause PPR (note that some components, such as table, trigger partial targets on only a subset of their events). For these cases where you need strict control over the event that launches PPR, or for cases where you want to use some logic to determine the target, you can implement PPR programatically.

Tip:

If your application uses the Fusion technology stack, you can enable the automatic partial page rendering feature on any page. This causes any components whose values change as a result of backend business logic to be automatically rerendered. For more information, see the "What You May Need to Know About Automatic Partial Page Rendering" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.

Additionally, ADF Faces applications can use PPR for navigation. In standard JSF applications, the navigation from one page to the next requires the new page to be rendered. When using AJAX-like components, this can cause overhead because of the time needed to download the different JavaScript libraries and style sheets. To avoid this costly overhead, the ADF Faces architecture can optionally simulate full-page transitions while actually remaining on a single page, thereby avoiding the need to reload JavaScript code and skin styles.

Note:

The browser must have JavaScript enabled for PPR to work.

7.2 Enabling Partial Page Rendering Declaratively

Using the simplest form of cross-component rendering, one component, referred to as the target component, is rerendered when any event occurs on another component, referred to as the trigger component.

For example, as shown in Figure 7-1, the File Explorer application contains a table that shows the search results in the Search panel. This table (and only this table) is rerendered when the search button is activated. The search button is configured to be the trigger and the table is configured to be the target.

Figure 7-1 The Search Button Causes Results Table to Rerender

Search button causes table to rerender

Note:

In some cases, you may want a component to be rerendered only when a particular event is fired, not for every event associated with the trigger component, or you may want some logic to determine whether a component is to be rerendered. In these cases, you can programatically enable PPR. For more information, see Section 7.3, "Enabling Partial Page Rendering Programmatically."

Trigger components must inform the framework that a PPR request has occurred. On command components, this is achieved by setting the partialSubmit attribute to true. Doing this causes the command component to fire a partial page request each time it is clicked.

For example, say a page includes an inputText component, a commandButton component, and an outputText component. When the user enters a value for the inputText component, and then clicks the commandButton component, the input value is reflected in the outputText component. You would set the partialSubmit attribute to true on the commandButton component.

However, components other than command components can trigger PPR. ADF Faces input and select components have the ability to trigger partial page requests automatically whenever their values change. To make use of this functionality, use the autoSubmit attribute of the input or select component so that as soon as a value is entered, a submit occurs, which in turn causes a valueChangeEvent event to occur. It is this event that notifies the framework to execute a PPR, as long as a target component is set. In the previous example, you could delete the commandButton component and instead set the inputText component's autoSubmit attribute to true. Each time the value changes, a PPR request will be fired.

Tip:

The autoSubmit attribute on an input component and the partialSubmit attribute on a command component are not the same thing. When partialSubmit is set to true, then only the components that have values for their partialTriggers attribute will be processed through the lifecycle. The autoSubmit attribute is used by input and select components to tell the framework to automatically do a form submit whenever the value changes. However, when a form is submitted and the autoSubmit attribute is set to true, a valueChangeEvent event is invoked, and the lifecycle runs only on the components marked as root components for that event, and their children. For more information, see Section 4.3, "Using the Optimized Lifecycle."

Once PPR is triggered, any component configured to be a target will be rerendered. You configure a component to be a target by setting the partialTriggers attribute to the relative ID of the trigger component. For information about relative IDs, see Section 3.5, "Locating a Client Component on a Page."

In the example, to update the outputText in response to changes to the inputText component, you would set its partialTriggers attribute to the inputText component's relative ID.

Note:

Certain events on components trigger PPR by default, for example the disclosure event on the showDetail component and the sort event on a table. This means that any component configured to be a target by having its partialTriggers attribute set to that component's ID will rerender when these types of events occur.

Note:

If your trigger component is an inputLov or an inputComboBoxLov, and the target component is an input component set to required, then a validation error will be thrown for the input component when the LOV popup is displayed. To avoid this, you must use programmatic partial page rendering. For more information, see Section 7.3, "Enabling Partial Page Rendering Programmatically."

7.2.1 How to Enable Partial Page Rendering

For a component to be rerendered based on an event caused by another component, it must declare which other components are the triggers.

To enable a component to rerender another component:

  1. In the Structure window, select the trigger component (that is, the component whose action will cause the PPR):

    • Expand the Common section of the Property Inspector and set the id attribute if it is not already set. Note that the value must be unique within that component's naming container. If the component is not within a naming container, then the ID must be unique to the page. For more information about naming containers, see Section 3.5, "Locating a Client Component on a Page."

      Tip:

      JDeveloper automatically assigns component IDs. You can safely change this value. A component's ID must be a valid XML name, that is, you cannot use leading numeric values or spaces in the ID. JSF also does not permit colons ( : ) in the ID.

    • If the trigger component is a command component, expand the Behavior section of the Property Inspector, and set the partialSubmit attribute to true.

    • If the trigger component is an input or select component in a form and you want the value to be submitted, expand the Behavior section of the Property Inspector, and set the autoSubmit attribute of the component to true.

      Note:

      Set the autoSubmit attribute to true only if you want the component to submit its value. If you do not want to submit the value, then some other logic must cause the component to issue a ValueChangeEvent event. That event will cause PPR by default and any component that has the trigger component as its value for the partialTriggers attribute will be rerendered.

  2. In the Structure window, select the target component that you want to rerender when a PPR-triggering event takes place.

  3. Expand the Behavior section of the Property Inspector, click the dropdown menu for the partialTriggers attribute and choose Edit.

  4. In the Edit Property dialog, shuttle the trigger component to the Selected panel and click OK. If the trigger component is within a naming container, JDeveloper automatically creates the relative path for you.

Tip:

The selectBooleanRadio components behave like a single component with partial page rendering;, however, they are in fact multiple components. Therefore, if you want other components (such as inputText components) to change based on selecting a different selectBooleanRadio component in a group, you must group them within a parent component, and set the partialTriggers attribute of the parent component to point to all of the SelectBooleanRadio components.

Example 7-1 shows a commandLink component configured to execute PPR.

Example 7-1 Code for Enabling Partial Page Rendering Through a Partial Submit

<af:commandLink id="deleteFromCart" partialSubmit="true"
                actionListener="#{homeBean...}">

Example 7-2 shows an outputText component that will be rerendered when the command link with ID deleteFromCart in Example 7-1 is clicked.

Example 7-2 Code for Partial Page Rendering Triggered by Another Component

<af:outputText id="estimatedTotalInPopup"
               partialTriggers="deleteFromCart"
               value="#{shoppingCartBean...}"/>

Tip:

You can use PPR to prevent components from being validated on a page. For more information, see Section 4.3, "Using the Optimized Lifecycle."

7.2.2 What You May Need to Know About Using the Browser Back Button

In an ADF Faces application, because some components use PPR (either implicitly or because they have been configured to listen for a partial trigger), what happens when a user clicks the browser's back button is slightly different than in an application that uses simple JSF components.

In an application that uses simple JSF components, when the user clicks the browser's back button, the browser returns the page to the state of the DOM (document object model) as it was when last rendered, but the state of the JavaScript is as it was when the user first entered the page.

For example, suppose a user visited PageA. After the user interacts with components on the page, say a PPR event took place using JavaScript. Let's call this new version of the page PageA1. Next, say the user navigates to PageB, then clicks the browser back button to return to PageA. The user will be shown the DOM as it was on PageA1, but the JavaScript will not have run, and therefore parts of the page will be as they were for PageA. This might mean that changes to the page will be lost. Refreshing the page will run the JavaScript and so return the user to the state it was in PageA1. In an application that uses ADF Faces, the refresh is not needed; the framework provides built-in support so that the JavaScript is run when the back button is clicked.

7.2.3 What You May Need to Know About PPR and Screen Readers

Screen readers do not reread the full page in a partial page request. PPR causes the screen reader to read the page starting from the component that fired the partial page request. You should place the target components after the component that triggers the partial request; otherwise, the screen reader would not read the updated target components.

7.3 Enabling Partial Page Rendering Programmatically

For components such as calendars that have many associated events, PPR will happen any time any event is triggered, causing any component with the calendar as a partial trigger to be rerendered with each event. If you want the target to be rerendered only for certain events, or if you want a target to be rerendered based on some other logic, you can enable partial page rendering programmatically.

For example, in the ADF Faces calendar demo, if a user attempts to change the duration of an activity that no longer exists in the model, the calendar needs to be refreshed to display without the activity (the calendar automatically refreshes itself if a valid activity's duration is changed). In this example, the activityDurationChangeListener method sets the calendar as a partial target whenever the activityDurationChangeEvent is invoked, and the activity object is null.

Before you begin:

Create a managed bean that will contain the listener method. For more information, see Section 2.6, "Creating and Using Managed Beans."

How to enable PPR programatically:

  1. In the JSF page, select the target component. In the Property Inspector, enter the set ClientComponent to true.

    Note:

    You must set the clientComponent attribute to true to ensure that the client ID will be generated.

  2. Use the binding attribute so that the managed bean can work with an instance of the target component. To do so:

    1. In the Property Inspector, set the Binding to an EL expression that resolves to the target component on the managed bean.

      In the above example, you might set Binding to:

      #{myBean.cal1}
      

      Where cal1 is the ID of the target component, in this case, the calendar component.

    2. In the managed bean, create get and set methods for the target component. Example 7-3 shows what the code on a managed bean might look like for the calendar component.

      Example 7-3 Get and Set Methods for a UI Component

      public class MyBean {
          private RichCalendar cal1;
         
          public MyBean() {
          }
       
        public void setCal1(RichCalendar cal1) {
            this.cal1 = cal1;
        }
       
        public RichOutputText getCal1() {
            return cal1;
        }
      
  3. In the managed bean, create a listener method for the event on the trigger component that should cause the target component to be rerendered.

    Use the addPartialTarget() method to add the component (using its ID) as a partial target for an event, so that when that event is triggered, the partial target component is rerendered. Using this method associates the component you want to have rerendered with the event that is to trigger the rerendering.

    Example 7-4 shows how you might create a ActivityDurationChangeEvent listener that adds the calendar as a target.

    Example 7-4 Rerendering Using Partial Targets

    public void activityDurationChangeListener(CalendarActivityDurationChangeEvent ae)
      {
        CalendarActivity activity = ae.getCalendarActivity();
     
        if (activity == null)
        {
          // no activity with that id is found in the model
          System.out.println("No activity with event " + ae.toString());
          setCurrActivity(null);
     
          // Since the user has acted on an activity that couldn't be found, 
          // ppr the page so that they no longer see the activity
          RequestContext adfContext = RequestContext.getCurrentInstance();
          adfContext.addPartialTarget(getCal1());
          return;
        }
     
        DemoCalendarActivity demoActivity = ((DemoCalendarActivity)activity);
        TimeZone tz = getTimeZone();
        demoActivity.setEndDate(ae.getNewEndDate(), tz);
        setCurrActivity(new DemoCalendarActivityBean(demoActivity, tz));
      }
    
  4. Select the trigger component, and in the Property Inspector, find the listener for the event that will cause the refresh and bind it to the listener method created in Step 3.

7.4 Using Partial Page Navigation

Instead of performing a full page transition in the traditional way, you can configure an ADF Faces application to have navigation triggered through a partial page rendering request. The new page is sent to the client using partial page rendering. Partial page navigation is disabled by default.

In order to keep track of location (for example, for bookmarking purposes, or when a refresh occurs), the framework makes use of the hash portion of the URL. This portion of the URL contains the actual page being displayed in the browser.

7.4.1 How to Use Partial Page Navigation

You can turn partial page navigation on by setting the oracle.adf.view.rich.pprNavigation.OPTIONS context parameter in the web.xml file to on.

To use partial page navigation:

  1. Double-click the web.xml file.

  2. In the source editor, change the oracle.adf.view.rich.prNavigation.OPTIONS parameter to one of the following:

    • on: Enables partial page navigation.

      Note:

      If you set the parameter to on, then you need to set the partialSubmit attribute to true for any command components involved in navigation.

    • onWithForcePPR: Enables partial page navigation and notifies the framework to use the PPR channel for all action events, even those that do not result in navigation. Since partial page navigation requires that the action event be sent over PPR channel, use this option to easily enable partial page navigation.

      When partial page navigation is used, normally only the visual contents of the page are rerendered (the header content remains constant for all pages). However, the entire document will be rerendered when an action on the page is defined to use full page submit and also when an action does not result in navigation.

7.4.2 What You May Need to Know About PPR Navigation

Before using PPR navigation, you should be aware of the following:

  • When using PPR navigation, all pages involved in this navigation must use the same CSS skin.

  • Because PPR navigation makes use of the hash portion of the URL, you cannot use the hash portion for navigation to anchors within the page.

  • Unlike regular page navigation, partial navigation will not result in JavaScript globals (variables and functions defined in global scope) being unloaded. This happens because the window object survives partial page transition. Applications wishing to use page-specific global variables and/or functions must use the AdfPage.getPageProperty() and AdfPage.setPageProperty() methods to store these objects.