Oracle® Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework 11g Release 1 (11.1.1.5.0) Part Number B31973-09 |
|
|
PDF · Mobi · ePub |
This chapter describes the JSF page request lifecycle and the additions to the lifecycle from ADF Faces, and how to use the lifecycle properly in your application.
This chapter includes the following sections:
Because the ADF Faces rich client framework (RCF) extends the JSF framework, any application built using the ADF Faces rich client framework uses the standard JSF page request lifecycle. However, the ADF Faces framework extends that lifecycle, providing additional functionality, such as a client-side value lifecycle, a subform component that allows you to create independent submittable regions on a page without the drawbacks (for example, lost user edits) of using multiple forms on a single page, and additional scopes.
To better understand the lifecycle enhancements that the RCF delivers, it is important that you understand the standard JSF lifecycle. This section provides only an overview. For a more detailed explanation, refer to the JSF specification at http://www.oracle.com/technetwork/java/index.html
.
When a JSF page is submitted and a new page is requested, the JSF page request lifecycle is invoked. This lifecycle handles the submission of values on the page, validation for components on the current page, navigation to and display of the components on the resulting page, as well as saving and restoring state. The JSF lifecycle phases use a UI component tree to manage the display of the faces components. This tree is a runtime representation of a JSF page: each UI component tag in a page corresponds to a UI component instance in the tree. The FacesServlet
object manages the page request lifecycle in JSF applications. The FacesServlet
object creates an object called FacesContext
, which contains the information necessary for request processing, and invokes an object that executes the lifecycle.
Figure 4-1 shows the JSF lifecycle of a page request. As shown, events are processed before and after each phase.
In a JSF application, the page request lifecycle is as follows:
Restore View: The component tree is established. If this is not the initial rendering (that is, if the page was submitted back to server), the tree is restored with the appropriate state. If this is the initial rendering, the component tree is created and the lifecycle jumps to the Render Response phase.
Apply Request Values: Each component in the tree extracts new values from the request parameters (using its decode method) and stores the values locally. Most associated events are queued for later processing. If a component has its immediate
attribute set to true
, then the validation, the conversion, and the events associated with the component are processed during this phase. For more information, see Section 4.2, "Using the Immediate Attribute."
Process Validations: Local values of components are converted from the input type to the underlying data type. If the converter fails, this phase continues to completion (all remaining converters, validators, and required checks are run), but at completion, the lifecycle jumps to the Render Response phase.
If there are no failures, the required
attribute on the component is checked. If the value is true
, and the associated field contains a value, then any associated validators are run. If the value is true
and there is no field value, this phase completes (all remaining validators are executed), but the lifecycle jumps to the Render Response phase. If the value is false
, the phase completes, unless no value is entered, in which case no validation is run. For more information about conversion and validation, see Chapter 6, "Validating and Converting Input."
At the end of this phase, converted versions of the local values are set, any validation or conversion error messages and events are queued on the FacesContext
object, and any value change events are delivered.
Tip:
In short, for an input component that can be edited, the steps for the Process Validations phase is as follows:If a converter fails, the required check and validators are not run.
If the converter succeeds but the required check fails, the validators are not run.
If the converter and required check succeed, all validators are run. Even if one validator fails, the rest of the validators are run. This is because when the user fixes the error, you want to give them as much feedback as possible about what is wrong with the data entered.
For example suppose you have a dateTimeRange
validator that accepted dates only in the year 2010, and you had a dateRestrictionValidator
validator that did not allow the user to pick Sundays. If the user entered July 5, 2009
(a Sunday), you want to give the feedback that this fails both validators to maximize the chance the user will enter valid data.
Update Model Values: The component's validated local values are moved to the model, and the local copies are discarded.
Invoke Application: Application-level logic (such as event handlers) is executed.
Render Response: The components in the tree are rendered. State information is saved for subsequent requests and for the Restore View phase.
To help illustrate the lifecycle, consider a page that has a simple input text component where a user can enter a date and then click a command button to submit the entered value. A valueChangeListener
method is also registered on the component. Example 4-1 shows the code for the example.
Example 4-1 Sample Code to Illustrate the JSF Lifecycle
<af:form> <af:inputText value="#{mybean.date}" valueChangeListener="#{mybean.valueChangeListener}"> <af:convertDateTime dateStyle="long"/> </af:inputText> <af:commandButton text="Save" actionListener="#{mybean.actionListener}"/> </af:form>
Suppose a user enters the string "June 25, 2005" and clicks the submit button. Figure 4-2 shows how the values pass through the lifecycle and where the different events are processed.
You can use the immediate
attribute to allow processing of components to move up to the Apply Request Values phase of the lifecycle. When actionSource
components (such as a commandButton
) are set to immediate
, events are delivered in the Apply Request Values phase instead of in the Invoke Application phase. The actionListener
handler then calls the Render Response phase, and the validation and model update phases are skipped.
For example, you might want to configure a Cancel button to be immediate
, and have the action return a string used to navigate back to the previous page (for more information about navigation, see Chapter 18, "Working with Navigation Components"). Because the Cancel button is set to immediate
, when the user clicks the Cancel button, all validation is skipped, any entered data is not updated to the model, and the user navigates as expected, as shown in Figure 4-3.
Note:
A command button that does not provide any navigation and is set toimmediate
will also go directly to the Render Response phase: the Validation, Update Model, and Invoke Application phases are skipped, so any new values will not be pushed to the server.As with command components, for components that invoke disclosure events, (such as a showDetail
component), and for editableValueHolder
components (components that hold values that can change, such as an inputText
component) the events are delivered to the Apply Request Values phase. However, for editableValueHolder
components, instead of skipping phases, conversion, validation, and delivery of valueChangeEvents
events are done earlier in the lifecycle, during the Apply Request Values phase, instead of after the Process Validations phase. No lifecycle phases are skipped.
Figure 4-4 shows the lifecycle for an input component whose immediate
attribute is set to true
. The input component takes a date entered as a string and stores it as a date object when the command button is clicked.
Setting immediate
to true
for an input component can be useful when one or more input components must be validated before other components. Then, if one of those components is found to have invalid data, validation is skipped for the other input components in the same page, thereby reducing the number of error messages shown for the page.
immediate
attribute to true
can lead to better performance:
When you create a navigation train, and have a commandNavigationItem
component in a navigationPane
component, you should set the immediate
attribute to true
to avoid processing the data from the current page (train stop) while navigating to the next page. For more information, see Section 18.8.1, "How to Create the Train Model."
If an input component value has to be validated before any other values, the immediate
attribute should be set to true
. Any errors will be detected earlier in the lifecycle and additional processing will be avoided.
As another example, suppose you have a form with an input component used to search for a string with a command button configured to invoke the search execution, and another input text component used to input a date with an associated command button used to submit the date. In this example, we want to set the search input component and its button both to be immediate
. This will allow the user to execute a search, even if an invalid string is entered into the date field, because the date input component's converter is never fired. Also, because the search input text is set to immediate
and the date input field is not, only the search input text will be processed. And because both fields are within the same form, if the user enters a valid date in the date field, but then performs a search and does not click the Save button, the entered value will still be displayed when the search results are displayed. Example 4-2 shows the code used for the two fields and two buttons.
Example 4-2 Input Component and Command Components Using Immediate
<af:form> <af:inputText immediate="true" label="Search" value="#{mybean.search}" valueChangeListener="#{mybean.searchValueChangeListener}"/> <af:commandButton immediate="true" text="search" actionListener="#{mybean.searchActionListener}"/> [.... tags to render search result ....] <af:inputText label="Date" value="#{mybean.date}" valueChangeListener="#{mybean.valueChangeListener}"> <af:convertDateTime dateStyle="long"/> </af:inputText> <af:commandButton text="save" actionListener="#{mybean.actionListener}"/> </af:form>
Figure 4-5 shows the lifecycle for this page when a user does the following:
Enters binky
into the Date input field (which is not a valid entry)
Enters dress
into the Search field
Clicks the Search button to execute the search on dress
Clicks the Save button to save the value binky
as the date
When using the immediate
attribute for editableValueHolder
and actionSource
components on the same page, note the following issues:
If an editableValueHolder
component is marked as immediate
, it will execute before the Update Model Values phase. This could be an issue when an immediate actionSource
component requires data from an editableValueHolder
component, as data entered into an editableValueHolder
component is not available to the model until after the Update Model Values phase. If you have an immediate actionSource
component, and that component needs data, then set immediate
on the editableValueHolder
fields as well. Then, you can call the getValue
method on the editableValueHolder
component and the local value will be returned. It will not have been pushed into the model yet, but it will be available on the component.
If an immediate editableValueHolder
component fails validation, any immediate actionSource
component will still execute.
To use the immediate attribute:
On the JSF page, select the component that you want to be immediate.
In the Property Inspector, expand the Behavior section and set the immediate
attribute to true
.
ADF Faces provides an optimized lifecycle that you can use when you want the JSF page request lifecycle (including conversion and validation) to be run only for certain components on a page. For example, suppose you have an inputText
component on a page whose required attribute is set to true
. On the same page are radio buttons that when selected cause the page to either show or hide text in an outputText
component, as shown in Figure 4-6.
Also assume that you want the user to be able to select a radio button before entering the required text into the field. While you could set the radio button components to automatically trigger a submit action and also set their immediate
attribute to true
so that they are processed before the inputText
component, you would also have to add a valueChangeEvent
listener, and in it call the Render Response phase so that validation is not run on the input text component.
Instead of having to write this code in a listener, ADF Faces allows you to set boundaries 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. This component can be determined in two ways:
Components: A region is an example of a component which the framework knows is a boundary. No matter what event is triggered inside a region, the lifecycle does not run on components outside the region.
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, and so the lifecycle is run only on the showDetail
component and any child components. The lifecycle may also be run on any components configured to listen for that disclosure event. Configuring a component to listen for events on root components in order to be processed is called cross-component refresh.
Cross-component refresh allows you to set up dependencies so that the events from one component act as triggers for another component, known as the target. When any event occurs on the trigger component, the lifecycle is run on any target components, as well as on any child components of both the trigger and the target, causing only those components to be rerendered. This is considered a partial page rendering (PPR).
In the radio button example, you would set the radio buttons to be triggers and the panelGroupLayout
component that contains the output text to be the target, as shown in Example 4-3.
Example 4-3 Example of Cross-Component Rendering
<af:form> <af:inputText label="Required Field" required="true"/> <af:selectBooleanRadio id="show" autoSubmit="true" text="Show" value="#{validate.show}"/> <af:selectBooleanRadio id="hide" autoSubmit="true" text="Hide" value="#{validate.hide}"/> <af:panelGroupLayout partialTriggers="show hide" id="panel"> <af:outputText value="You can see me!" rendered="#{validate.show}"/> </af:panelGroupLayout> </af:form>
Because the autoSubmit
attribute is set to true
on the radio buttons, when they are selected, a SelectionEvent
is fired, for which the radio button is considered the root. Because the panelGroupLayout
component is set to be a target to both radio components, when that event is fired, only the selectOneRadio
(the root), the panelGroupLayout
component (the root's target), and its child component (the outputText
component) are processed through the lifecycle. Because the outputText
component is configured to render only when the Show radio button is selected, the user is able to select that radio button and see the output text, without having to enter text into the required input field above the radio buttons.
For more information about how the ADF Faces framework uses PPR, and how you can use PPR throughout your application, see Chapter 7, "Rerendering Partial Page Content."
There may be cases where PPR will not be able to keep certain components from being validated. For example, suppose instead of using an outputText
component, you want to use an inputText
component whose required
attribute is set to true
, inside the panelGroupLayout
component, as shown in Example 4-4.
Example 4-4 inputText Component Within a panelGroup Component Will Be Validated with Cross-Component PPR
<af:form>
<af:selectBooleanRadio id="show2" autoSubmit="true" text="Show"
value="#{validate.show2}"/>
<af:selectBooleanRadio id="hide2" autoSubmit="true" text="Hide"
value="#{validate.hide2}"/>
<af:panelGroupLayout partialTriggers="show2 hide2">
<af:inputText label="Required Field" required="true"
rendered="#{validate.show2}"/>
</af:panelGroupLayout>
</af:form>
In this example, the inputText
component will be validated because the lifecycle runs on the root (the selectOneRadio
component), the target (the panelGroupLayout
component), and the target's child (the inputText
component). Validation will fail because the inputText
component is marked as required and there is no value, so an error will be thrown. Because of the error, the lifecycle will skip to the Render Response phase and the model will not be updated. Therefore, the panelGroupLayout
component will not be able to show or hide because the value of the radio button will not be updated.
For cases like these, you can skip validation using the immediate
attribute on the radio buttons. Doing so causes the valueChangeEvent
on the buttons to run before the Process Validation phase of the inputText
component. Then you need to add a valueChangeListener
handler method that would call the Render Response phase (thereby skipping validation of the input component), and set the values on the radio buttons and input component. Example 4-5 shows the JSF code to do this.
Example 4-5 Using the immediate Attribute and a valueChangeListener
<af:form> <af:selectOneRadio immediate="true" valueChangeListener="#{validate.toggle}" id="show2" autoSubmit="true" text="Show" value="#{validate.show2}"/> <af:selectOneRadio id="hide2" autoSubmit="true" text="Hide" value="#{validate.hide2}"/> <af:panelGroupLayout partialTriggers="show2 hide2"> <af:inputText label="Required Field" required="true" rendered="#{validate.show2}"/> </af:panelGroupLayout> </af:form>
Example 4-6 shows the valueChangeListener
code.
For the inputListOfValues
and inputComboBoxListOfValues
components, the procedures described in Section 4.3.1, "What You May Need to Know About Using the Immediate Attribute and the Optimized Lifecycle," will not work. Consider the following example.
Suppose you have an inputListOfValues
component from which a user selects an employee name, and an inputText
component whose required attribute is set to true
, which is updated with the employee's ID number once the employee is selected, as shown in Figure 4-7.
To achieve this, you might set the Empno field to have the Ename field as a partial trigger, as shown in Example 4-7.
Example 4-7
<af:inputListOfValues label="Ename" id="lov0" value="#{validateLOV.ename}" autoSubmit="true" immediate="true" popupTitle="Search and Select: Ename" searchDesc="Choose a name" model="#{validateLOV.listOfValuesModel}" valueChangeListener="#{validateLOV.immediateValueChange}" validator="#{validateLOV.validate}"/> <af:inputText label="Empno" value="#{validateLOV.empno}" required="true" id="lovDependent01" partialTriggers="lov0"/>
As with the radio button and input component example in Section 4.3.1, "What You May Need to Know About Using the Immediate Attribute and the Optimized Lifecycle," once the user clicks the search icon, the inputText
component will be validated because the lifecycle runs on both the root (the inputListOfValues
component) and the target (the inputText
component). Validation will fail because the inputText
component is marked as required and there is no value, so an error will be thrown, as shown in Figure 4-8.
However, the solution recommended in Section 4.3.1, "What You May Need to Know About Using the Immediate Attribute and the Optimized Lifecycle," of setting the LOV component's immediate attribute to true
and using a ValueChange
Listener on the LOV will not fix the validation error. For LOV components, the ValueChangeEvent
is queued only when the value of the LOV component changes. For this reason, setting the immediate
attribute to true
has no effect when the user clicks the search icon, because at that point the ADF LaunchPopupEvent
is queued for the Invoke Application phase always, regardless of the value of the immediate
attribute. In other words, the optimized lifecycle is run as normal on both the root and target components and therefore the input component throws a validation error.
When the user selects a new value from the LOV popup, the LOV component queues two events. One is a ValueChangeEvent
to signal a change in value for the component. The second is a ReturnPopupEvent
queued for the Invoke Application phase, which gives application methods a chance to handle the selection. Both these events need to occur in order for the LOV to behave as expected.
As mentioned, the LOV component queues a ValueChangeEvent
only when the user selects a new value. If you were to set the immediate
attribute to true
on the LOV component, this event would be queued for the Apply Request Values phase and the new value would be validated. In addition if you were to create a ValueChangeListener
method for the LOV component, and in its implementation jump to the Render Response phase to avoid validation of the input component, the selected value would never get pushed to the model, the ReturnPopupListener
would never get called during the Invoke Application phase, and the target input component would not get updated with new value, as shown in Figure 4-9.
To resolve this issue of needing both the ValueChangeEvent
and the ReturnPopupEvent
to be queued as part of the same request and to have any target fields refreshed with newly selected values, instead of declaratively setting the LOV component as a partial trigger for the input component and creating a method for the ValueChangeListener
, you need to create a listener for the ReturnPopupEvent
. This listener must programmatically set the input components as partial targets for the LOV. You do not need to set the LOV's immediate
attribute to true
because the input component is no longer a target for the LOV until the ReturnPopupListener
method is executed, and so it will not fail validation because the lifecycle will not be run on it. And because a listener method is used for the ReturnPopupEvent
instead of for the ValueChangeEvent
, both events can be queued and the model updated appropriately.
Example 4-8 shows the needed page code for the LOV and input components.
Example 4-8
<af:inputListOfValues label="Ename" id="lov1" value="#{validateLOV.ename}" autoSubmit="true" returnPopupListener="#{validate.processReturnPopup}" Title="Search and Select: Ename" searchDesc="Choose a name" model="#{validateLOV.listOfValuesModel}" validator="#{validateLOV.validate}"/> <af:inputText label="Empno" value="#{validateLOV.empno}" required="true" id="lovDependent1" binding="#{validate.lovDependent1}"/>
The input component uses its binding
attribute to store the instance on a backing bean, allowing the instance to be accessed by the listener method. The listener method then accesses the input component and sets it as a partial target for the LOV, as shown in Example 4-9.
For more information about programmatically setting partial page rendering, see Section 7.3, "Enabling Partial Page Rendering Programmatically."
The ADF Faces framework provides client-side conversion and validation. You can create your own JavaScript-based converters and validators that run on the page without a trip to the server.
You can use client-side validation so that when a specific client event is queued, it triggers client validation of the appropriate form or subform (for more information about subforms, see Section 4.5, "Using Subforms to Create Regions on a Page"). If this client validation fails, meaning there are known errors, then the events that typically propagate to the server (for example, a command button's actionEvent
when a form is submitted) do not go to the server. Having the event not delivered also means that nothing is submitted and therefore, none of the client listeners is called. This is similar to server-side validation in that when validation fails on the server, the lifecycle jumps to the Render Response phase; the action event, though queued, will never be delivered; and the actionListener
handler method will never be called.
For example, ADF Faces provides the required
attribute for input components, and this validation runs on the client. When you set this attribute to true
, the framework will show an error on the page if the value of the component is null
, without requiring a trip to the server. Example 4-10 shows code that has an inputText
component's required
attribute set to true
, and a command button whose actionListener
attribute is bound to a method on a managed bean.
Example 4-10 Simple Client-Side Validation Example
<af:form> <af:inputText id="input1" required="true" value="a"/> <af:commandButton text="Search" actionListener="#{demoForm.search}"/> </af:form>
When this page is run, if you clear the field of the value of the inputText
component and tab out of the field, the field will redisplay with a red outline. If you then click into the field, an error message will state that a value is required, as shown in Figure 4-10. There will be no trip to the server; this error detection and message generation is all done on the client.
In this same example, if you were to clear the field of the value and click the Search button, the page would not be submitted because the required field is empty and therefore an error occurs; the action event would not be delivered, and the method bound to the action listener would not be executed. This process is what you want, because there is no reason to submit the page if the client can tell that validation will fail on the server.
For more information about using client-side validation and conversion, see Chapter 6, "Validating and Converting Input."
In the JSF reference implementation, if you want to independently submit a region of the page, you have to use multiple forms. However multiple forms require multiple copies of page state, which can result in the loss of user edits in forms that aren't submitted.
ADF Faces adds support for a subform component, which represents an independently submittable region of a page. The contents of a subform will be validated (or otherwise processed) only if a component inside of the subform is responsible for submitting the page, allowing for comparatively fine-grained control of the set of components that will be validated and pushed into the model without the compromises of using entirely separate form elements. When a page using subforms is submitted, the page state is written only once, and all user edits are preserved.
form
tag per page. Use the subform
tag where you might otherwise be tempted to use multiple form
tags.A subform will always allow the Apply Request Values phase to execute for its child components, even when the page was submitted by a component outside of the subform. However, the Process Validations and Update Model Values phases will be skipped (this differs from an ordinary form component, which, when not submitted, cannot run the Apply Request Values phase). To allow components in subforms to be processed through the Process Validations and Update Model Value phases when a component outside the subform causes a submit action, use the default
attribute. When a subform's default
attribute is set to true
, it acts like any other subform in most respects, but if no subform on the page has an appropriate event come from its child components, then any subform with default
set to
true
will behave as if one of its child components caused the submit. For more information about subforms, see Section 9.2, "Defining Forms."
At runtime, you pass data to pages by storing the needed data in an object scope where the page can access it. The scope determines the lifespan of an object. Once you place an object in a scope, it can be accessed from the scope using an EL expression. For example, you might create a managed bean named foo
, and define the bean to live in the Request scope. To access that bean, you would use the expression #{requestScope.foo}
.
There are three types of scopes in a standard JSF application:
application
Scope
: The object is available for the duration of the application.
session
Scope
: The object is available for the duration of the session.
request
Scope
: The object is available for the duration between the time an HTTP request is sent until a response is sent back to the client.
In addition to the standard JSF scopes, ADF Faces provides the following scopes:
pageFlow
Scope
: The object is available as long as the user continues navigating from one page to another. If the user opens a new browser window and begins navigating, that series of windows will have its own pageFlowScope
scope.
backingBean
Scope
: Used for managed beans for page fragments and declarative components only. The object is available for the duration between the time an HTTP request is sent until a response is sent back to the client. This scope is needed because there may be more than one page fragment or declarative component on a page, and to avoid collisions between values, any values must be kept in separate scope instances. Use backingBeanScope
scope for any managed bean created for a page fragment or declarative component.
view
Scope
: The object is available until the ID for the current view changes. Use viewScope
scope to hold values for a given page.
Note:
Because these are not standard JSF scopes, EL expressions must explicitly include the scope to reference the bean. For example, to reference theMyBean
managed bean from the pageFlowScope
scope, your expression would be #{pageFlowScope.MyBean}
.Object scopes are analogous to global and local variable scopes in programming languages. The wider the scope, the higher the availability of an object. During their lifespan, these objects may expose certain interfaces, hold information, or pass variables and parameters to other objects. For example, a managed bean defined in sessionScope
scope will be available for use during multiple page requests. However, a managed bean defined in requestScope
scope will be available only for the duration of one page request.
Figure 4-11 shows the time period in which each type of scope is valid, and its relationship with the page flow.
When determining what scope to register a managed bean with or to store a value in, always try to use the narrowest scope possible. Use the sessionScope
scope only for information that is relevant to the whole session, such as user or context information. Avoid using the sessionScope
scope to pass values from one page to another.
Note:
If you are using the full Fusion technology stack, then you have the option to register your managed beans in various configuration files. For more information, see the "Using a Managed Bean in a Fusion Web Application" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.Note:
If you are using the full Fusion technology stack and you need information about passing values between pages in an ADF bounded task flow, or between ADF regions and pages, refer to the "Getting Started With ADF Task Flows" chapter of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.The ADF Faces pageFlowScope
scope makes it easier to pass values from one page to another, thus enabling you to develop master-detail pages more easily. Values added to the pageFlowScope
scope automatically continue to be available as the user navigates from one page to another, even if you use a redirect
directive. But unlike session
scope, these values are visible only in the current page flow or process. If the user opens a new window and starts navigating, that series of windows will have its own process. Values stored in each window remain independent.
Like objects stored in any standard JSF scope, objects stored in the pageFlow
scope can be accessed through EL expressions. The only difference with the pageFlow
scope is that the object names must use the pageFlow
Scope
prefix. For example, to have a button's label provided by a managed bean stored in the pageFlow
scope, and to have a method on the bean called when the button is selected, you might use the following code on your page:
<af:commandButton text="#{pageFlowScope.buttonBean.label}" action="#{pageFlowScope.buttonBean.action}"/>
The pageFlowScope
is a java.util.Map
object that may be accessed from Java code. The setPropertyListener
tag allows you to set property values onto a scope, and also allows you to define the event the tag should listen for. For example, when you use the setPropertyListener
tag with the type
attribute set to action
, it provides a declarative way to cause an action source (for example, commandButton
) to set a value before navigation. You can use the pageFlowScope
scope with the setPropertyListener
tag to pass values from one page to another, without writing any Java code in a backing bean. For example, you might have one page that uses the setPropertyListener
tag and a command component to set a value in the pageFlowScope
scope, and another page whose text components use the pageFlowScope
scope to retrieve their values.
You can also use the pageFlowScope
scope to set values between secondary windows such as dialogs. When you launch secondary windows from, for example, a commandButton
component, you can use a launchEvent
event and the pageFlowScope
scope to pass values into and out of the secondary windows without overriding values in the parent process.
You can access pageFlow
scope from within any Java code in your application. Remember to clear the scope once you are finished.
Note:
If your application uses ADF Controller, then you do not have to manually clear the scope.To use pageFlowScope in Java code:
To get a reference to the pageFlowScope
scope, use the org.apache.myfaces.trinidad.context.RequestContext. getPageFlowScope()
method.
For example, to retrieve an object from the pageFlowScope
scope, you might use the following Java code:
import java.util.Map; import org.apache.myfaces.trinidad.context.RequestContext; . . . Map pageFlowScope = RequestContext.getCurrentInstance().getPageFlowScope(); Object myObject = pageFlowScope.get("myObjectName");
To clear the pageFlowScope
scope, access it and then manually clear it.
For example, you might use the following Java code to clear the scope:
RequestContext afContext = RequestContext.getCurrentInstance(); afContext.getPageFlowScope().clear();
To use the pageFlowScope
scope without writing Java code, use a setPropertyListener
tag in conjunction with a command component to set a value in the scope. The setPropertyListener
tag uses the type
attribute that defines the event type it should listen for. It ignores all events that do not match its type. Once set, you then can access that value from another page within the page flow.
Tip:
Instead of using thesetActionListener
tag (which may have been used in previous versions of ADF Faces), use the setPropertyListener
tag and set the event type to action
.To set a value in the pageFlowScope scope:
On the page from where you want to set the value, create a command component using the Component Palette.
In the Component Palette, from the Operations panel, drag a Set Property Listener and drop it as a child to the command component.
Or right-click the component and choose Insert inside Button > ADF Faces > setPropertyListener.
In the Insert Set Property Listener dialog, set the From field to the value that will be set on another component.
For example, say you have a managed bean named MyBean
that stores the name value for an employee, and you want to pass that value to the next page. You would enter #{myBean.empName}
in the From field.
Set the To field to be a value on the pageFlowScope
scope.
For example, you might enter #{pageFlowScope.empName}
in the To field.
From the Type dropdown menu, choose Action.
This allows the listener to listen for the action event associated with the command component.
To access a value from the pageFlowScope scope:
On the page from which you want to access the value, drop the component that you want to display the value.
Set the value of the component to be the same value as the To
value set on the setPropertyListener
tag.
For example, to have an outputText
component access the employee name, you would set the value of that component to be #{pageFlowScope.empName}
.
When a user clicks a command button that contains a setPropertyListener
tag, the listener executes and the To
value is resolved and retrieved, and then stored as a property on the pageFlowScope
scope. On any subsequent pages that access that property through an EL expression, the expression is resolved to the value set by the original page.