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:
Section 7.2, "Enabling Partial Page Rendering Declaratively"
Section 7.3, "Enabling Partial Page Rendering Programmatically"
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.8, "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.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.
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:
TheautoSubmit
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 thedisclosure
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 aninputLov
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."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:
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 theautoSubmit
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.In the Structure window, select the target component that you want to rerender when a PPR-triggering event takes place.
Expand the Behavior section of the Property Inspector, click the dropdown menu for the partialTriggers
attribute and choose Edit.
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:
TheselectBooleanRadio
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."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.
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.
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.
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:
In the JSF page, select the target component. In the Property Inspector, enter the set ClientComponent to true.
Note:
You must set theclientComponent
attribute to true
to ensure that the client ID will be generated.Use the binding
attribute so that the managed bean can work with an instance of the target component. To do so:
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.
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.
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)); }
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.
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.
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:
Double-click the web.xml
file.
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 toon
, 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.
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.