Skip Headers
Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3)
B25386-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

6.4 Incorporating Range Navigation into Forms

When you choose to add navigation when you use the Data Control Palette to create an input form, 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 the data objects in the collection. Figure 6-6 shows a form that contains navigation buttons.

Figure 6-6 Navigation in a Form

Navigation buttons in the detail page for search results

6.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 using navigation operation controls.

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 ServiceRequest collection of the findAllServiceRequest() method. Figure 6-7 shows the navigation operations associated with a collection.

    Figure 6-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.

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

When you drop an 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

6.4.2.1 Using Action Bindings for Built-in Navigation Operations

Action bindings execute business logic. Action bindings can invoke methods on a business service (for example, the method action binding for a method used by an iterator to access a collection) or as in the case of navigation controls, 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.


Note:

For more information about using methods to add, remove, or update data, see Chapter 10, "Creating Command Components to Execute Methods".

Like value bindings, action bindings for navigation operations must also contain a reference to the iterator binding, 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. Example 6-8 shows the action bindings for the navigation operations.

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

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

6.4.2.2 Iterator RangeSize Attribute

Iterator bindings have a rangeSize attribute used to determine the number of data objects to return 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 another set, creating a new range. Example 6-9 shows the range size for the findAllServiceRequestIter iterator.


Note:

This rangeSize attribute is not the same as the rangeSize attribute on your data table.

Example 6-9 RangeSize Attribute for an Iterator

<executables>
  <methodIterator id="findAllServiceRequestIter"
                      Binds="findAllServiceRequest.result"
                      DataControl="SRPublicFacade" RangeSize="10"
                      BeanClass="oracle.srdemo.model.entities.ServiceRequest"/>
</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.


Tip:

You can also set a range of records directly in the query you write on your business service. However, doing so means every page that uses the query will return the same range size. By setting the range size on the iterator, you can control the size per page.

Table 6-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 6.4.3, "What Happens at Runtime: About Action Events and Action Listeners".

Table 6-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.

SetCurrentRowWithKey

96

Set the row key as a String converted from the value specified by the input field. The row key is used to set the currency of the data object in the bound data collection. For an example of when this is used, see Section 7.7.1, "How to Manually Set the Current Row".

SetCurrentRowWithKeyValue

98

Set the current object on the iterator, given a key's value.


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.

6.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 6.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 is not enabled (for example, if the current record is the first record, the First operation should not be enabled), then the button is disabled. Example 6-10 shows the code generated on the JSF page for navigation operation buttons.

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

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

6.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.

6.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 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 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 6-11 shows a page definition file after token validation was set to true.

Example 6-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">