Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g Release 3 (10.1.3.0)
B25947-01
  Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

13.4 Incorporating Range Navigation into Forms

When you create an ADF Form, you are given the option of adding navigation. If you choose to do so, JDeveloper includes ADF Faces command components bound to existing navigational logic on the data control. This built-in logic allows the user to navigate through all the data objects in the collection. Figure 13-6 shows a form that contains navigation buttons.

Figure 13-6 Navigation in a Form

Navigation buttons in the detail page for search results

13.4.1 How to Insert Navigation Controls into a Form

By default, when you choose to include navigation when creating a form using the Data Control Palette, JDeveloper creates First, Last, Previous, and Next buttons that allow the user to navigate within the collection.

You can also add navigation buttons to an existing form manually.

To manually add navigation buttons:

  1. From the Data Control Palette, select the operation associated with the collection of objects on which you wish the operation to execute, and drag it onto the JSF page.

    For example, if you want to navigate through service requests, you would drag the Next operation associated with the ServiceRequests collection. Figure 13-7 shows the operations associated with a collection.

    Figure 13-7 Navigation Operations Associated With a Collection

    Navigation operations in the Data Control Palette
  2. Choose either Command Button or Command Link from the context menu.

13.4.2 What Happens When Command Buttons Are Created Using the Data Control Palette

When you drop any operation as a command component, JDeveloper:

  • Defines an action binding in the page definition file for the associated operations

  • Inserts code in the JSF page for the command components

13.4.2.1 Using Action Bindings for Built-in Navigation Operations

Action bindings execute business logic. For example, they can invoke built-in methods on the action binding object. These built-in methods operate on the iterator or on the data control itself, and are represented as operations in the Data Control Palette. JDeveloper provides navigation operations that allow users to navigate forward, backwards, to the last object in the collection, and to the first object.

Like value bindings, action bindings for operations will contain a reference to the iterator binding when the action binding is bound to one of the iterator-level actions, such as Next or Previous, as it is used to determine the current object and can therefore determine the correct object to display when each of the navigation buttons is clicked (action bindings to other than iterator-level actions, for example for a custom method on an AM, or for the commit or rollback operations, will not contain this reference). Example 13-8 shows the action bindings for the navigation operations.


Tip:

The numerical values of the Action attribute in the <action> tags (as shown in Figure 13-7) are defined in the oracle.adf.model.meta.OperationDefinition class. However, when you use the ADF Model layer's action binding editor, you never need to set the numerical code by hand.

Example 13-8 Page Definition Code for an Operation Action Binding

 <action id="First" RequiresUpdateModel="true" Action="12"
            IterBinding="ServiceRequestsIterator"/>
 <action id="Previous" RequiresUpdateModel="true" Action="11"
            IterBinding="ServiceRequestsIterator"/>
 <action id="Next" RequiresUpdateModel="true" Action="10"
            IterBinding="ServiceRequestsIterator"/>
 <action id="Last" RequiresUpdateModel="true" Action="13"
            IterBinding="ServiceRequestsIterator"/>

13.4.2.2 Iterator RangeSize Attribute

Iterator bindings have a rangeSize attribute used to determine the number of data objects to make available for the page for each iteration. This attribute helps in situations when the number of objects in the data source is quite large. Instead of returning all objects, only a set number are returned and accessible by the other bindings. Once the iterator reaches the end of the range, it accesses the next set. Example 13-9 shows the default range size for the ServiceRequestsIterator iterator.


Note:

This rangeSize attribute is not the same as the row attribute on a table component. For more information, see Table 14-1, "ADF Faces Table Attributes and Populated Values".

Example 13-9 RangeSize Attribute for an Iterator

<executables>
  <iterator id="ServiceRequestsIterator" RangeSize="10"
            Binds="ServiceRequests" DataControl="SRService"/>
</executables>

By default, the rangeSize attribute is set to 10. This means that a user can view 10 objects, navigating back and forth between them, without needing to access the data source. The iterator keeps track of the current object. Once a user clicks a button that requires a new range (for example, clicking the Next button on object number 10), the binding object executes its associated method against the iterator, and the iterator retrieves another set of 10 records. The bindings then work with that set. You can change this setting as needed. You can set it to -1 to have the full record set returned. The default is -1 for iterator bindings that furnish a list of valid choices for list bindings.

Table 13-1 shows the built-in navigation operations provided on data controls, along with the action attribute value set in the page definition, and the result of invoking the operation or executing an event bound to the operation. For more information about action events, see Section 13.4.3, "What Happens at Runtime: About Action Events and Action Listeners".

Table 13-1 Built-in Navigation Operations

Operation Action Attribute Value When invoked, the associated iterator binding will...

Next

10

Move its current pointer to the next object in the result set. If this object is outside the current range, the range is scrolled forward a number of objects equal to the range size.

Previous

11

Move its current pointer to the preceding object in the result set. If this object is outside the current range, the range is scrolled backward a number of objects equal to the range size.

First

12

Move its current pointer to the beginning of the result set.

Last

13

Move its current pointer to the end of the result set.

Next Set

14

Move the range forward a number of objects equal to the range size attribute.

Previous Set

15

Move the range backward a number of objects equal to the range size attribute.


Every action binding for an operation has an enabled boolean property that the ADF framework sets to false when the operation should not be invoked. You can then bind the UI component to this value to determine whether or not the component should be enabled. For more information about the enabled property, see Appendix B, "Reference ADF Binding Properties".

13.4.2.3 Using EL Expressions to Bind to Navigation Operations

When you create command components using navigation operations, the components are placed in a panelButtonBar component. JDeveloper creates an EL expression that binds a navigational command button's actionListener attribute to the execute property of the action binding for the given operation. This expression causes the binding's operation to be invoked on the iterator when a user clicks the button.

For more information about the command button's actionListener attribute, see Section 13.4.3, "What Happens at Runtime: About Action Events and Action Listeners". For example, the First command button's actionListener attribute is bound to the execute method on the First action binding.

The disabled attribute is used to determine if the button should be inactivated. For example, if the user is currently displaying the first record, the First button should not be able to be clicked. The code uses an EL expression that evaluates to the enabled property on the action binding. If the property value is not true (for example, if the current record is the first record, the First operation should not be enabled), then the button is disabled. Example 13-10 shows the code generated on the JSF page for navigation operation buttons.

Example 13-10 JSF Code for Navigation Buttons Bound to ADF Operations

<f:facet name="footer">
   <af:panelButtonBar>
     <af:commandButton actionListener="#{bindings.First.execute}"
                         text="First"
                         disabled="#{!bindings.First.enabled}"/>
     <af:commandButton actionListener="#{bindings.Previous.execute}"
                       text="Previous"
                       disabled="#{!bindings.Previous.enabled}"/>
     <af:commandButton actionListener="#{bindings.Next.execute}"
                       text="Next"
                       disabled="#{!bindings.Next.enabled}"/>
     <af:commandButton actionListener="#{bindings.Last.execute}"
                       text="Last"
                       disabled="#{!bindings.Last.enabled}"/>
   </af:panelButtonBar>
   <af:commandButton text="Submit"/>
 </f:facet>

13.4.3 What Happens at Runtime: About Action Events and Action Listeners

An action event occurs when a command component is activated. For example, when a user clicks a button, the form the component is enclosed in is submitted, and subsequently an action event is fired. Action events might affect only the user interface (for example, a link to change the locale, causing different field prompts to display), or they might involve some logic processing in the back end (for example, a button to navigate to the next record).

An action listener is a class that wants to be notified when a command component fires an action event. An action listener contains an action listener method that processes the action event object passed to it by the command component.

In the case of the navigation operations, when a user clicks, for example, the Next button, an action event is fired. This event stores currency information about the current data object, taken from the iterator. Because the component's actionListener attribute is bound to the execute method of the Next action binding, the Next operation is invoked. This method takes the currency information passed in the event object to determine what the next data object should be.

13.4.4 What You May Need to Know About the Browser Back Button

When a user clicks the navigation buttons, the iterator determines the next data object to display. However, when the user clicks the browser's Back button, the action and/or event is not shared outside the browser, and the iterator is bypassed. Therefore, when a user clicks a browser's Back button instead of using navigation buttons on the page, the iterator becomes out of sync with the page displayed, causing unexpected results.

For example, say a user browses to object 103, and then uses the browser's Back button. Because the browser shows the page last visited, object 102 is shown. However, the iterator still thinks the current object is 103 because the iterator was bypassed. If the user were to then to click the Next button, object 104 would display because that is what the iterator believes to be the next object, and not 103 as the user would expect.

Because the iterator and the page are out of sync, problems can arise when a user edits records. For example, if the user were to have edited object 102 after clicking the browser's Back button, the changes would have actually been posted to 103, because this is what the iterator thought was the current object.

To prevent a user making changes to the wrong object instances, you can use token validation. When you enable token validation for a page, that page is annotated with the current object for all the iterators used to render that page. This annotation is encoded onto the HTML payload rendered to the browser and is submitted to the server along with any data. At that point, the current object of the iterator is compared with the annotation. If they are different, an exception is thrown.

For example, in the earlier scenario, when the user starts at 103 but then clicks the browser's Back button to go to 102, as before, the previous page is displayed. However, that page was (and still is) annotated with 102. Therefore, when the user clicks the Next button to submit the page and navigate forward, the annotation (102) does not match the iterator (which is still at 103), an exception is thrown, and the Next operation is not executed. The page renders with 103, which is the object the iterator believed to be current. An error displays on the page stating that 102 was expected, since the server expected 102 based on the annotation submitted with the data. Since 103 is now displayed, both the annotation and the iterator are now at 103, and are back in sync.

Token validation is set on the page definition for a JSF page. By default, token validation is on.

To set token validation:

  1. Open the page definition file for the page.

  2. In the Structure window, select the root node for the page definition itself.

  3. In the Property Inspector, use the dropdown list for the EnableTokenValidation attribute to set validation to true to turn on token validation, or false to turn off token validation.

Example 13-11 shows a page definition file after token validation was set to true.

Example 13-11 Enable Token Validation in the Page Definition File

<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel"
                version="10.1.3.35.29" id="createProductPageDef"
                Package="oracle.srdemo.view.pageDefs"
                EnableTokenValidation="true">