Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g Release 3 (10.1.3.0)

Part Number B25947-02
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

14 Adding Tables

This chapter describes how to use the Data Control Palette to create databound tables using ADF Faces components.

This chapter includes the following sections:

14.1 Introduction to Adding Tables

Unlike forms, tables allow you to display more than one data object from a collection at a time. Figure 14-1 shows the SRList page in the SRDemo application, which uses a browse table to display the current service requests for a logged in user.

Figure 14-1 The Service Request Table

The SRList page contains a table that lists service requests

Once you drop a collection as a table, you can then add row selection components that allow users to select a specific row. When you add command buttons bound to actions, users can then click those buttons to execute some logic on the selected row. For more information, see Section 17.3, "Creating Command Components to Execute Methods". You can also modify the default components to suit your needs.

Read this chapter to understand:

14.2 Creating a Basic Table

Unlike with forms, where you bind the individual UI components that make up a form to the individual attributes on the collection, with a table you bind the ADF Faces table component to the complete collection or to a range of N data objects at a time from the collection. The individual columns in the table are then bound to the attributes. The iterator binding handles displaying the correct data for each object, while the table component handles displaying each object in a row. JDeveloper allows you to do this declaratively, so that you don't need to write any code.

14.2.1 How to Create a Basic Table

To create a table using a data control, you bind the table component to a view object collection. JDeveloper allows you to do this declaratively by dragging and dropping a collection from the Data Control Palette.

To create a databound table:

  1. From the Data Control Palette, select a collection.

    For example, to create the SRList table in the SRDemo application, you select the ServiceRequestsByStatus collection that is under the LoggedInUser collection. Figure 14-2 shows the ServiceRequestsByStatus collection in the Data Control Palette.

    Figure 14-2 ServiceRequestsByStatus Collection in the Data Control Palette

    ServiceRequestsByStatus collection

    The ServiceRequestsByStatus collection, which extends ServiceRequests, is a child of the LoggedInUser collection because of the view link ServiceRequestsForUser. The ServiceRequestsByStatus collection also has a named bind variable StatusCode that represents the service request status type (for example, open or pending requests). In the SRList page, when the logged in user selects a command link in the menu bar to view open, pending, closed, or all service requests, the requests created by or assigned to the currently logged in user for the selected status type are returned.

  2. Drag the collection onto a JSF page, and from the context menu, choose the appropriate table.

    When you drag the collection, you can choose from the following types of tables:

    • ADF Table: Allows you to select the specific attributes you wish your editable table columns to display, and what UI components to use to display the data. By default, each attribute on the collection object is displayed in an inputText component, thus enabling the table to be editable.

    • ADF Read-Only Table: Same as the ADF Table; however, each attribute is displayed in an outputText component.

    • ADF Read-Only Dynamic Table: The attributes returned and displayed are determined dynamically. This component is helpful when the attributes for the corresponding object are not known until runtime, or you do not wish to hardcode the column names in the JSF page. For example, if you have a polymorphic collection (for example, a view object collection that can be a collection of mammals or a collection of birds), the dynamic table can display the different attributes accordingly.

    • ADF Master Table, Inline Detail Table: For more information, see Section 15.6, "Using an Inline Table to Display Detail Data in a Master Table".

  3. From the ensuing Edit Table Columns dialog, you can do the following:

    • Change the display label for a column. By default, the label is bound to the labels property for the attribute on the table binding. For more information about the labels property, see Appendix B, "Reference ADF Binding Properties". The bindings to the labels property allow the labels to be inherited from the UI control hints that you have defined in your business domain layer, thus enabling you to change the value of a label text once in a central place, and have the change appear the same on all pages that display the label. In the Edit Table Columns dialog, you can instead enter text or an EL expression to bind the label value to something else, for example, a key in a resource file.

      For example, the heading for the Status column in the table on the SRList page is bound to the labels property that uses the Status key to get the attribute:

      #{bindings.LoggedInUserServiceRequests.labels.Status}
      

      However, you could change the heading to instead be bound to a key in a properties resource file, for example:

      #{srlist['sr.status']}
      

      In the example, srlist would be a variable defined in the JSF page used to load a properties file. For more information about using resource bundles, see Section 22.4, "Internationalizing Your Application".

      Note that the SRDemo pages mainly use the inherited UI control hints for all attributes, and JSF resource strings for other kinds of labels that are not directly related to view object attributes.

    • Change the attribute binding for a column.

      For example, you can change the status column to instead be bound to the requestDate attribute. If you simply want to rearrange the columns, you should use the order buttons, as described later in the section. If you do change the attribute binding for a column, note the following:

      • If you change the binding, the label for the column also changes.

      • If you change the binding to an attribute currently bound to another column, the UI component changes to a component different from that used for the column currently bound to that attribute.

    • Change the UI component used to display an attribute. The UI components are either inputText or outputText and are set based on the table you selected when you dropped the collection onto the page. You can change to the other component using the dropdown menu. If you want to use a different component, such as a command link or button, you need to use this dialog to select the outputText component, and then in the Structure window, replace the component with the desired UI component (such as a command link).

    • Change the order of the columns using the order buttons. Top moves the column to the first column at the left of the table. Up moves the column one column to the left. Down moves the column one to the right. Bottom moves the column to the very right.

    • Add a column using the New button. There's no limit to the number of columns you can add. When you first click New, JDeveloper adds a new column line at the bottom of the dialog and populates it with default values from the first attribute in the bound collection; subsequent new columns are populated with values from the next attribute in the sequence, and so on.

    • Delete a column using the Delete button. Doing so deletes the column from the table.

    • Add a tableSelectOne component to the table's selection facet by selecting Enable selection. For more information, see Section 14.6, "Enabling Row Selection in a Table".

    • Allow sorting for all columns by selecting Enable sorting.

14.2.2 What Happens When You Use the Data Control Palette to Create a Table

Dropping a table from the Data Control Palette has the same effect as dropping a text field or form. For more information, see Section 13.2.2, "What Happens When You Use the Data Control Palette to Create a Text Field". Briefly, JDeveloper does the following:

  • Creates the bindings for the table and adds the bindings to the page definition file.

  • Adds the necessary code for the UI components to the JSF page.

14.2.2.1 Iterator and Value Bindings for Tables

When you drop a table from a the Data Control Palette, a table value binding is created. Like an attribute binding used in forms, the table value binding references the iterator binding; the iterator binding references an iterator for the data collection, which facilities iterating over the data objects in the collection. Instead of creating a separate binding for each attribute, only the table binding is created. In the table binding, the AttrNames element contains a a child element for each attribute that you want to be available for display or reference in each row of the table. Example 14-1 shows the value binding for the table created when you drop the ServiceRequestsByStatus collection.

Example 14-1 Value Binding Entries for a Table in the Page Definition File

<table id="LoggedInUserServiceRequests"
       IterBinding="ServiceRequestsByStatusIterator">
  <AttrNames>
    <Item Value="SvrId"/>
    <Item Value="Status"/>
    <Item Value="RequestDate"/>
    <Item Value="ProblemDescription"/>
    <Item Value="ProdId"/>
    <Item Value="CreatedBy"/>
    <Item Value="AssignedTo"/>
    <Item Value="AssignedDate"/>
  </AttrNames>
</table>

Only the table value binding is needed because only the table UI component needs access to the data. The table columns derive their information from the table binding.

14.2.2.2 Code on the JSF Page for an ADF Faces Table

When you use the Data Control Palette to drop a table onto a JSF page, JDeveloper creates a table that contains a column for each attribute on the object to which it is bound. To do this, JDeveloper inserts an ADF Faces table component, which contains an ADF Faces column component for each attribute named in the table binding. Each column then contains either an input or outputText component bound to the attribute's value. Each column's heading is bound to the labels property for the attribute on the table binding. Example 14-2 shows a simplified code excerpt from the table on the SRList page.

Example 14-2 Simplified JSF Code for an ADF Faces Table

<af:table value="#{bindings.LoggedInUserServiceRequests.collectionModel}"
          var="row" ..>
  ...
  <af:column headerText="#{bindings.LoggedInUserServiceRequests.labels.Status}"
             sortProperty="Status" sortable="false">
    <af:outputText value="#{row.Status}"/>
  </af:column>
  <af:column
           headerText="#{bindings.LoggedInUserServiceRequests.labels.RequestDate}"
           sortProperty="RequestDate" sortable="false">
    <af:outputText value="#{row.RequestDate}">
      <f:convertDateTime 
           pattern="#{bindings.LoggedInUserServiceRequests.formats.RequestDate}"/>
    </af:outputText>
  </af:column>
  ...   
</af:table>

The table binding iterates over the data exposed by the iterator binding. The FacesCtrlRangeBinding class extends the base JUCtrlRangeBinding class to add specific methods to the base table binding object; one of the methods is the getCollectionModel method, which the EL accesses using the collectionModel property of the table binding. The table wraps the result set from the iterator binding in an oracle.adf.view.faces.model.CollectionModel object. As the table binding iterates, it makes each item in the collection available within the table component using the var attribute.

In the example, the table iterates over the rows in the current range of the ServiceRequestsByStatusIterator iterator binding. The iterator binding binds to a row set iterator that keeps track of the current row. When you set the var attribute on the table to row, each column then accesses the current data object for the current row presented to the table tag using the row variable, as shown for the value of the af:outputText tag:

<af:outputText value="#{row.Status}"/>

Table 14-1 shows the other attributes defined by default for ADF Faces tables created using the Data Control Palette.

Table 14-1 ADF Faces Table Attributes and Populated Values

Attribute Description Default Value

rows

Determines how may rows to display at one time.

An EL expression that evaluates to the rangeSize property of the associated iterator binding. For more information on this attribute, see Section 14.3, "Incorporating Range Navigation into Tables". Note that the value of the rows attribute is equal to or less than the corresponding iterator's rangeSize value.

first

Index of the first row in a range (based on 0).

An EL expression that evaluates to the rangeStart property of the associated iterator binding. For more information on this attribute, see Section 14.3, "Incorporating Range Navigation into Tables".

emptyText

Text to display when there are no rows to return.

An EL expression that evaluates to the viewable property on the iterator. If the table is viewable, displays No rows yet when no objects are returned. If the table is not viewable (for example if there are authorization restrictions set against the table), displays Access Denied.

Column Attributes

   

sortProperty

Determines the property on which to sort the column.

Set to the columns corresponding attribute binding value.

sortable

Determines whether a column can be sorted

Set to false. When set to true, the table will sort only the rows returned by the iterator.


Additionally, a table may also have a selection facet, and selection and selectionListener attributes if you chose to enable selection when you created your table. For more information, see Section 14.6, "Enabling Row Selection in a Table".

14.3 Incorporating Range Navigation into Tables

Instead of using built-in operations to perform navigation as forms do, ADF Faces tables provide built-in navigation using the selectRangeChoiceBar component that is automatically included with table components. The selectRangeChoiceBar component renders a dropdown menu and Previous and Next links for selecting a range of records to display in the current page. Figure 14-3 shows an example of how the selectRangeChoiceBar component might look like in a table.

Figure 14-3 SelectRangeChoiceBar in a Table

SRList table can navigate through sets of service requests

14.3.1 How to Use Navigation Controls in a Table

The rows attribute on a table component determines the maximum number of rows to display in a range. When you use the Data Control Palette to create a table, by default JDeveloper sets the table to display a range of rows equal to the iterator's rangeSize value, as shown in the following code snippet for the rows attribute on the SRList table:

<af:table rows="#{bindings.LoggedInUserServiceRequests.rangeSize}".../>

The EL expression in the rows attribute evaluates to the iterator's range size, which is defined in the page definition file:

<executables>
  <iterator id="ServiceRequestsByStatusIterator" RangeSize="10"
            Binds="ServiceRequestsByStatus" DataControl="SRService"/>
  </executables>

By default, the RangeSize value is 10, which means that 10 records are returned at a time for display in the current page.

To change the number of records to return for display in the current page, edit the RangeSize value in the page definition file (instead of editing directly the rows attribute on the table component).

If you change the rows attribute on the table component directly instead of changing the RangeSize value on the iterator, make sure the value of rows is equal to or less than the iterator's RangeSize value. For additional information about the RangeSize attribute, see Section 13.4.2.2, "Iterator RangeSize Attribute".

14.3.2 What Happens When You Use Navigation Controls in a Table

The selectRangeChoiceBar component provides navigational links that allow a user to select the next and previous range of objects in the collection. If the total size of the collection is known, the component provides a dropdown menu that lets the user navigate directly to a particular range set in the collection (as illustrated in Figure 14-3). When you change the RangeSize attribute on the iterator, the selectRangeChoiceBar component automatically changes to show the new range sets.

The rows attribute on a table component is used in conjunction with the first attribute to set the ranges. The first attribute, which is a zero-based index of the rows in a range, determines the first row in the current range. By default, the rows attribute uses an EL expression that binds its value to the value of the rangeSize attribute of the associated iterator. The first attribute also uses an EL expression, but the expression binds to the value of the iterator's rangeStart attribute. For example, the rows and first attribute on the table on the SRList page have the following values:

<af:table rows="#{bindings.LoggedInUserServiceRequests.rangeSize}"
          first="#{bindings.LoggedInUserServiceRequests.rangeStart}"

Each current range starts with the row identified by first, and contains only as many rows as indicated by the rows attribute.

14.3.3 What Happens at Runtime

To determine the range sets for the selectRangeChoiceBar to use, the view object retrieves the first "RangeSize" number of rows and then stops, and the table makes a separate SELECT COUNT(*) FROM (...) query by calling the getEstimatedRowCount() method, which estimates the total number of rows the query would retrieve without actually retrieving them all. For more information about the getEstimatedRowCount() method, see Section 5.6.2, "Counting the Number of Rows in a RowSet".

Unlike navigation operations which rely on logic in an action binding to provide navigation, the selectRangeChoiceBar component sends a RangeChangeEvent event. When a user navigates to a different range by selecting one of the navigation links provided by the selectRangeChoiceBar component, (such as Previous or Next), the table generates a RangeChangeEvent event. This event includes the index of the object that should now be at the top of the range. The table responds to this event by changing the value of the first attribute to this new index.

The RangeChangeEvent event has an associated listener. You can bind the RangeChangeListener attribute on the table to a method on a managed bean. This method will then be invoked in response to the RangeChangeEvent event, in other words whenever the table has changed the first attribute in response to the user changing a range on the table. This binding can be helpful when some complementary action needs to happen in response to user navigation, for example, if you need to release cached data created for a previous range. For information about adding logic before or after built-in operations, see Section 17.5, "Overriding Declarative Methods".

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

Note that using the browser Back button has the same issues as described in Chapter 13. For more information, see Section 13.4.4, "What You May Need to Know About the Browser Back Button". Because the iterator keeps track of the current object, 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 because the iterator has been bypassed. Like in forms, in tables the current row (or range or rows) displayed in the page you see when you use the browser Back button may no longer correspond with the iterator binding's notion of the current row and range.

For example, in the SRList page shown in Figure 14-1, if you select the service request with the ID of 4 and then navigate off the page using either the ID's link or the View or Edit buttons, the iterator is set to the object that represents service request 4. If you set EnableTokenValidation to be true (as described in the procedure in Section 13.4.4, "What You May Need to Know About the Browser Back Button"), then the page's token is also set to 4. When you use the browser's Back button, everything seems to be fine, the same range is displayed. However, if you click another button, an error indicating that the current row is out of sync is shown. This is because the page displayed is the previous page, whose token was set to 0, while the iterator is at 4.

14.4 Modifying the Attributes Displayed in the Table

Once you use the Data Control Palette to create a table, you can then delete attributes, change the order in which they are displayed, change the component used to display them, and change the attribute binding for the component. You can also add new attributes. Before you add new attributes, make sure the table binding includes the attribute you want to display in the table.

14.4.1 How to Modify the Displayed Attributes

You can modify the following aspects of a table that was created using the Data Control Palette.

  • Change the binding for the label of a column

  • Change the attribute to which a UI component is bound

  • Change the UI component bound to an attribute

  • Reorder the columns in the table

  • Delete a column in the table

  • Add a column to the table

To change the attributes for a table:

  1. In the Structure window, right-click af:table and choose Edit Columns.

  2. In the Edit Table Columns dialog, you can do the following:

    • Change the display label for the column. By default, the label is bound to the labels property for the attribute on the table binding. For more information about the labels property, see Appendix B, "Reference ADF Binding Properties". The bindings to the labels property allow the labels to be inherited from the UI control hints that you have defined in your business domain layer, thus enabling you to change the value of a label text once in a central place, and have the change appear the same on all pages that display the label. In this dialog, you can instead enter text or an EL expression to bind the label value to something else, for example, a key in a resource file.

      For example, the heading for the Status column in the table on the SRList page is bound to the labels property that uses the Status key to get the attribute:

      #{bindings.LoggedInUserServiceRequests.labels.Status}
      

      However, you could change it to instead be bound to a key in a properties resource file, for example:

      #{srlist['sr.status']}
      

      In this example, srlist would be a variable defined in the JSF page used to load a properties file. For more information about using resource bundles, see Section 22.4, "Internationalizing Your Application".

    • Change the attribute binding for a column.

      For example, you can change the Status column to instead be bound to the RequestDate attribute. Note the following:

      • If you change the binding, the label for the column also changes.

      • If you change the binding to an attribute currently bound to another column, the UI component changes to a component different from that used for the column currently bound to that attribute.

      If you simply want to rearrange the columns, you should use the order buttons, as described later in the section.

    • Change the UI component used to display the attribute. The UI components are either inputText or outputText and are set based on the composite component you selected when you dropped the collection onto the page. You can change to the other UI component using the dropdown menu. If you want to use an entirely different component, such as a command link or button, you need to use this dialog to change to an outputText component, and then in the Structure window, replace the outputText component with the desired UI component (such as a command link).

      Tip:

      You can use the following UI components in a table with the noted caveats:
      • The selectBooleanCheckbox component can be used inside a table if it is only handling boolean or java.lang.Boolean types.

      • The selectOneListbox/Choice/Radio components can be used inside the table if you manually add the list of choices as an enumeration. If instead you want to use a list binding, then the selectOne UI component cannot be used inside a table. For more information on list bindings, see Section 19.7, "Creating Selection Lists".

    • Change the order of the columns using the order buttons. Top moves the column to the first column at the left of the table. Up moves the column one column to the left. Down moves the column one to the right. Bottom moves the column to the very right.

    • Add a column using the New button. Doing so adds a new column at the bottom of the dialog and populates it by default with values from the next sequential attribute in the collection. You then need to edit the values. You can only select an attribute associated with the object to which the table is bound.

    • Delete a column using the Delete button. Doing so deletes the column from the table.

    • Add a tableSelectOne component to the table's selection facet by selecting Enable selection. For more information, see Section 14.6, "Enabling Row Selection in a Table".

    • Add sorting capabilities by selecting Enable sorting.

14.4.2 How to Change the Binding for a Table

Instead of modifying a binding, you can completely change the object to which the table is bound.

To rebind a table:

  1. Right-click the table in the Structure window and choose Edit Binding to launch the Table Binding Editor.

  2. In the editor, select the new collection to which you want to bind the table. Note that changing the binding for the table will also change the binding for all the columns. You can then use the procedures in Section 14.4.1, "How to Modify the Displayed Attributes" to modify those bindings.

14.4.3 What Happens When You Modify Bindings or Displayed Attributes

When you simply modify how an attribute is displayed, by moving the UI component or changing the UI component, JDeveloper changes the corresponding code on the JSF page. When you use the binding editors to add or change a binding, JDeveloper adds the code to the JSF page, and also adds the appropriate elements to the page definition file.

14.5 Adding Hidden Capabilities to a Table

You can use the detailStamp facet in a table to include data that can be displayed or hidden. When you add a component to this facet, the table displays an additional column labeled Details with a toggle. When the user activates the toggle, the component added to the facet is shown. When the user clicks on the toggle again, the component is hidden. For more information about facets in general, see Section 13.3.2.1, "Using Facets". Figure 14-4 shows how the description of a service request in an outputText component can be hidden or shown in the table (note that this functionality does not currently exist in the SRDemo application).

Figure 14-4 Table with an Output UI Component in the DetailStamp Facet

Problem description text can be hidden below the row.

If you wish to show details of another object that has a master-detail relationship (for example, if you wanted to show the details of the person to whom the service request is assigned), you could use the Master Table-Inline Detail composite component. For more information about master-detail relationships and the use of the master-detail composite component, see Section 15.6, "Using an Inline Table to Display Detail Data in a Master Table".

14.5.1 How to Use the DetailStamp Facet

To use the detailStamp facet, you insert a component that is bound to the data to be displayed or hidden into the facet. You can also set an attribute on the table that creates a link that allows a user to show or hide all details at once.

To use the detailStamp facet:

  1. From the Data Control Palette, drag the attribute to be displayed in the facet onto the detailStamp facet folder. Figure 14-5 shows how the detailStamp facet folder appears in the Structure window.

    Figure 14-5 The detailStamp Facet Folder in the Structure Window

    The detailStamp facet is one of many facets for a table
  2. From the ensuing context menu, choose the UI component to display the attribute.

  3. If you want a link to allow users to hide or show all details at once, select the table in the Structure window. Then in the Property Inspector, set the allDetailsEnabled attribute to true.

  4. If the attribute to be displayed is specific to a current record, then you need to replace the JSF code (which simply binds the component to the attribute), so that it uses the table's variable to display the data for the current record.

    For example, when you drag an attribute, JDeveloper inserts the following code:

    <f:facet name="detailStamp">
      <af:outputText value="#{bindings.<attributename>.inputValue}"/>
    </f:facet>
    

    You need to change it to the following:

    <f:facet name="detailStamp">
      <af:outputText value="#{row.<attributename>}"/>
    </f:facet>
    

14.5.2 What Happens When You Use the DetailStamp Facet

When you drag an attribute in the detailStamp facet folder, JDeveloper adds the attribute value binding to the page definition file if it did not already exist, and it also adds the code for facet to the JSF Page.

For example, say on the SRList page you want the user to be able to optionally hide the service request description. Since the table was created using the ServiceRequestsByStatus collection, you can drag the ProblemDescription attribute and drop it inside the detailStamp facet folder in the Structure window.

Example 14-3 shows the code JDeveloper then adds to the JSF page.

Example 14-3 JSF Code for a detailStamp Facet

<f:facet name="detailStamp">
  <af:outputText value="#{bindings.ServiceRequestsByStatusProblemDescription.inputValue}"/>
</f:facet>

You then need to change the code so that the component uses the table's variable to access the correct problem description for each row. Example 14-4 shows how the code should appear after using the row variable.

Example 14-4 Modified JSF Code for a detailStamp Facet

<f:facet name="detailStamp">
  <af:outputText value="#{row.ServiceRequestsByStatusProblemDescription}"/>
</f:facet>

14.5.3 What Happens at Runtime

When the user hides or shows the details of a row, the table generates a DisclosureEvent event (or a DisclosureAllEvent event when the allDetailsEnabled attribute on the table is set to true). The event tells the table to toggle the details (that is, either expand or collapse).

The DisclosureEvent event has an associated listener. You can bind the DisclosureListener attribute on the table to a method on a managed bean. This method will then be invoked in response to the DisclosureEvent event to execute any needed post-processing.

14.6 Enabling Row Selection in a Table

When the tableSelectOne component or the tableSelectMany component is added to the table's selection facet, the table displays a Select column that allows a user to select one row, or one or more rows, and then take some action on those rows via command buttons.

The tableSelectOne component allows the user to select just one row. This component provides a radio button for each row in the Select column, as shown in Figure 14-6. For example, the table in the SRList page has a tableSelectOne component that allows a user to select a row, and then click either the View or Edit command button to view or edit the details for the selected service request.

Figure 14-6 The SRList Table Uses the TableSelectOne Component

Users can select one row in the SRList table.

The tableSelectMany component displays a checkbox for each row in the Select column, allowing the user to select one or more rows. When you use the tableSelectMany component, text links are also added that allow the user to select all or none of the rows, as shown in Figure 14-7. For example, the table on the SRMain page has a tableSelectMany component that allows a user to select multiple records, and then click the Delete Service History Record command button to delete the selected records.

Figure 14-7 The Service History Table Uses the TableSelectMany Component

Users can select mulitple rows in the history table.

Both table row selection components have a text attribute whose value can be instructions for the user. The table row selection components also usually have command button or command links as children, which are used to perform some action on the selected rows. For example, the table on the SRList page has command buttons that allows a user to view or edit the selected service request.

You can set the required attribute on both the tableSelectOne and the tableSelectMany components to true. This value will cause an error to be thrown if the user does not select a row. However, if you set the required attribute, you must also set the summary attribute on the table in order for the required input error message to display correctly. For more information about the required attribute, see Section 20.3.1.1.1, "Using Validation Attributes".

You can also set the autoSubmit attribute on the tableSelectOne and the tableSelectMany components. When the autoSubmit attribute is set to true, the form that holds the table automatically submits when the user makes a selection. For more information, see Section 11.6, "Best Practices for ADF Faces".

The procedures for using the tableSelectOne and tableSelectMany are quite different. In ADF applications, operations (such as methods) work on the current data object, which the iterator keeps track of. The tableSelectOne component is able to show the current data object as being selected, and is also able to set a newly selected row to the current object on the iterator. If the same iterator is used on a subsequent page (for example, if the user selects a row and then clicks the command button to navigate to a page where the object can be edited), the selected object will be displayed. This works because the iterator and the component are working with a single object; the notion of the current row is the same because the different iterator bindings in different binding containers are bound to the same row set iterator.

However, with the tableSelectMany component, there are multiple selected objects. The ADF Model layer has no notion of "selected" as opposed to "current." You must add logic to the model layer that loops through each of the selected objects, making each in turn current, so that the operation can be executed against that object.

14.6.1 How to Use the TableSelectOne Component in the Selection Facet

When you drop a collection from the Data Control Palette as a table, you have the choice to include the selection facet. If you select Enable selection, a tableSelectOne component is inserted into the selection facet, along with a Submit commandButton component as a child of tableSelectOne.

Note:

You cannot insert a tableSelectMany component when you create a table using the Data Control Palette. You need to manually add it after creating the table. Note however, that you must create additional code in order to use multi-select processing in an ADF application. For more information, see Section 14.6.5, "How to Use the TableSelectMany Component in the Selection Facet".

If you wish to have the Submit button bound to a method, you need to rebind the commandButton component to the method or operation of your choice. For rebinding procedures, see Section 21.6, "Adding ADF Bindings to Actions".

You can also manually add a tableSelectOne component to a selection facet.

To manually use the selection facet:

  1. In the Structure window, select af:table and choose Edit Columns from the context menu.

  2. In the Edit Table Columns dialog, select Enable selection and click OK.

    JDeveloper adds the tableSelectOne component to the selection facet folder (plus the needed listener and attribute that work with selection on the table component).

  3. In the Structure window, expand the table's selection facet folder and select af:tableSelectOne.

  4. In the Property Inspector for the new component, enter a value for the text attribute that will provide instructions for using any command buttons or links used to process the selection.

  5. (Optional): Rebind the Submit command button to a method or operation of your choice from the Data Control Palette. For rebinding procedures, see Section 21.6, "Adding ADF Bindings to Actions". For more information about using methods to create command buttons, see Section 17.3, "Creating Command Components to Execute Methods".

    Note:

    Until you add a command component to the facet, the value for the text attribute will not display.

14.6.2 What Happens When You Use the TableSelectOne Component

As Example 14-5 shows, when you elect to enable selection as you first create or later edit a table, the tableSelectOne component is inserted into the selection facet with Select and as the value for the text attribute. A Submit command button is also included as a child.

Example 14-5 Selection Facet Code

<f:facet name="selection">
  <af:tableSelectOne text="Select and">
    <af:commandButton text="Submit"/>
</af:tableSelectOne>

As Example 14-6 shows, the table's selectionState attribute's value is an EL expression that evaluates to the selected row on the collection model created from the iterator. The selectionListener attribute's value evaluates to the makeCurrent method on the collection model. This value is what allows the selection facet to set the selected row as the current object on the iterator.

Example 14-6 Selection Attributes on a Table

<af:table var="row"
   rows="#{bindings.ServiceRequests.rangeSize}"
   first="#{bindings.ServiceRequests.rangeStart}"
   selectionState="#{bindings.ServiceRequests.collectionModel.selectedRow}"
   selectionListener="#{bindings.ServiceRequests.collectionModel.makeCurrent}"...>

14.6.3 What Happens at Runtime

Once the user makes a selection and clicks the associated command button, the tableSelectOne component updates the RowKeySet obtained by calling the getSelectionState() method on the table. Since the selection state evaluates to the selected row on the collection model, that row is marked as selected. This selection is done prior to calling the ActionListener associated with the command button.

For a tableSelectOne component, because the current row is selected before the ActionListener is invoked, you can bind the ActionListener on the command button to a method on a managed bean that provides the corresponding processing on the data in the row. Or you can simply add the logic to the declarative method. For more information, see Section 17.5, "Overriding Declarative Methods".

The tableSelectOne component triggers a SelectionEvent event when the selection state of the table is changed. The SelectionEvent reports which rows were selected and deselected. Because the SelectionListener attribute is bound to the makeCurrent method on the collection model, this method is invoked when the event occurs, and sets the iterator to the new current row.

14.6.4 What You May Need to Know About Using Links Instead of the Selection Facet

As described in Section 14.6.1, "How to Use the TableSelectOne Component in the Selection Facet", a commandButton component is automatically added as a child of the tableSelectOne component when you drop a collection as a table and select Enable selection at the same time, or when you use the Edit Table Columns dialog to enable selection later. The tableSelectOne component is inserted into the selection facet on the table component.

When the user makes a selection in the table, the tableSelectOne component sets the selected row as the current object on the iterator. Then the user can perform some action on the selected row via the command button.

Instead of using the selection facet components to set the current object and providing a commandButton to navigate to the next page, you can use a commandLink component that lets the user click a link to both perform an operation on a selection and navigate to another page. As shown in Figure 14-6, the second column of links in the table saves the user the step of having to first select a row and then click a command button to perform an action and navigate. If you add column links, you must manually set the current object on the iterator binding. For more information about manually setting the current object, see Section 14.7, "Setting the Current Object Using a Command Component".

Tip:

If the subsequent page does not use the same iterator, you will most likely have to manually set the parameter that represents the selected row for the subsequent page. For example, from the SRList page, when the user selects a service request and then clicks the Edit command button, the application navigates to the SREdit page, which displays the correct data for the selected service request. The Edit command button, which uses the setCurrentRowWithKey action binding, includes the af:setActionListener tag to set the appropriate value into processScope before navigation. The SREdit page has an invokeAction object that invokes the setCurrentRowWithKey operation; the value bound to the rowKey NamedData element is passed in as the parameter, which determines the current row to display. For more information, see Section 17.4, "Setting Parameter Values Using a Command Component".

14.6.5 How to Use the TableSelectMany Component in the Selection Facet

You cannot insert a tableSelectMany component when you create a table using the Data Control Palette. You need to manually add it after creating the table.

Unlike the tableSelectOne component, with the tableSelectMany component, there are multiple selected objects.

When you add the tableSelectMany component to a table that uses an ADF table binding, you need to pass the set of selected Keys to a method that processes each one in turn.

To use the tableSelectMany component in an ADF application:

  1. Create the table as shown in Section 14.2.1, "How to Create a Basic Table" but do not select Enable selection.

  2. In the Structure window, expand the Table facets folder, right-click the selection facet folder, and choose Insert inside selection > TableSelectMany.

  3. In the Structure window, select the af:table node and in the Property Inspector, delete the values for the SelectionState and SelectionListener attributes, if necessary. Doing so will keep the component from setting one of the selected rows to the current object, as you need this logic to be handled through the code you create.

  4. From the Data Control Palette, drag the method that will operate on the selected objects on top of the af:tableSelectMany node. From the ensuing context menu, choose Create > ADF Command Button. Doing so drops the method as a commandButton component. You need to set the parameter value for the method, if the method accepts parameters.

    For example, to create the SRMain page where a user can delete multiple service history records associated with a service request, you would drag the custom deleteServiceHistoryNotes(Set) operation onto the af:tableSelectMany node.

  5. In the Action Binding Editor, enter the value for the parameter by clicking the ellipses button (...) in the Value field to open the EL Expression Builder. Select the node that represents the value for the parameter.

    For example, the table on the SRMain page is bound to the historyTable property on the managed bean named backing_SRMain. To access the set of selected rows in the table, you would use the following as the value for the parameter:

    #{backing_SRMain.historyTable.selectionState.keySet}
    

    For more information, see Section 17.3.1, "How to Create a Command Component Bound to a Service Method".

  6. Add logic to allow the declarative method to operate against the set of selected rows. To add the logic, you override the declarative method created when the command button was dropped. For instructions, see Section 17.5, "Overriding Declarative Methods". Briefly, you override the declarative method by binding the command button's action attribute to a backing bean method that has the added logic. Example 14-11 shows the backing bean method onDeleteHistoryRows() created for the SRMain page.

14.6.6 What Happens When You Use the TableSelectMany Component

When you insert the tableSelectMany component into a table, and then add a command button bound to a service method, JDeveloper does the following:

  • Adds the tableSelectMany and commandButton components to the selection facet on the table component

  • Creates a method binding for the bound method in the page definition file, including a NamedData element to hold the value of the parameter needed for the method (if any), determined when you dropped the method as a button

Example 14-7 shows the code for the table, tableSelectMany, and commandButton components.

Example 14-7 JSF Code for a Table That Uses the TableSelectMany Component

<af:table value="#{bindings.ServiceHistories.collectionModel}" var="row"
          rows="#{bindings.ServiceHistories.rangeSize}"
          first="#{bindings.ServiceHistories.rangeStart}"...
          binding="#{backing_SRMain.historyTable}">
  <af:column headerText="#{bindings.ServiceHistories.labels.SvhDate}"
             sortable="false">
    <af:outputText value="#{row.SvhDate}">
      <f:convertDateTime pattern="#{bindings.ServiceHistories.formats.SvhDate}"/>
    </af:outputText>
  </af:column>
  <af:column headerText="#{bindings.ServiceHistories.labels.SvhType}"
             sortable="false">
    <af:outputText value="#{row.SvhType}"/>
  </af:column>
  <af:column headerText="#{bindings.ServiceHistories.labels.Notes}"
             sortable="false">
    <af:outputText value="#{row.Notes}"/>
  </af:column>
  <f:facet name="selection">
    <af:tableSelectMany text="Select items and ...">
      <af:commandButton text="..."
                    actionListener="#{bindings.deleteServiceHistoryNotes.execute}"
                         .../>
    </af:tableSelectMany>
  </f:facet>
</af:table>

When you create a command button using a custom service method, JDeveloper binds the button to the method using the actionListener attribute. The button is bound to the execute property of the action binding for the given method. Example 14-8 shows the page definition code that contains the method action binding for the bound method on the command button.

Example 14-8 DeleteServiceHistoryNotes Method Action Binding

<methodAction id="deleteServiceHistoryNotes"
              InstanceName="SRService.dataProvider" DataControl="SRService"
              MethodName="deleteServiceHistoryNotes"
              RequiresUpdateModel="true" Action="999">
  <NamedData NDName="keySet"
             NDValue="${backing_SRMain.historyTable.selectionState.keySet}"
             NDType="java.util.Set"/>
</methodAction>

The method action binding causes the associated method to be invoked on the business service, passing in the value bound to the NamedData element as the parameter.

Instead of binding the command button to the execute method on the action binding, you can bind the button to a method in a backing bean that overrides the declarative method. Doing so allows you to add logic before or after the original method runs. When you override a declarative method, JDeveloper automatically rebinds the command component to the new method using the action attribute (instead of the actionListener attribute), as shown in Example 14-9.

Example 14-9 Command Button Code After You Override the Declarative Method

<af:commandButton text="..."
                  action="#{backing_SRMain.onDeleteHistoryRows}"/>

Example 14-10 shows the binding container code that JDeveloper inserts into the backing bean when you override the declarative method. The code accesses the binding container and finds the binding for the associated method.

Example 14-10 Binding Container Code Added by JDeveloper in the Backing Bean

private BindingContainer bindings;

public BindingContainer getBindings() {
       return this.bindings;
}

public void setBindings(BindingContainer bindings) {
       this.bindings = bindings;
}

public String onDeleteHistoryRows() {
    BindingContainer bindings = getBindings();
    OperationBinding operationBinding = 
        bindings.getOperationBinding("deleteServiceHistoryNotes");
    Object result = operationBinding.execute();
    if (!operationBinding.getErrors().isEmpty()) {
        return null;
    }
    return null;
}

By adding logic before or after the execute() call on the method binding, you can perform needed logic before or after the declarative method.

14.6.7 What Happens at Runtime

Like the tableSelectOne component, when the user makes multiple selections with the tableSelectMany component and then clicks the associated command button, the tableSelectMany component updates the selection state of the table by placing all the rows selected by the user in a RowKeySet.

Example 14-11 shows the SRMain page backing bean method that overrides the declarative method created when the deleteServiceHistoryNotes(Set) operation is dropped as a command button.

Example 14-11 Backing Bean Method for Deleting Service History Records

public String onDeleteHistoryRows() {
  BindingContainer bindings = getBindings();
  Set keySet = getHistoryTable().getSelectionState().getKeySet();
  if (!keySet.isEmpty()) {
    getBindings().getOperationBinding("deleteServiceHistoryNotes").execute();
    keySet.clear();
  }
  return null;
}

Example 14-12 shows the code in the backing bean that you need to add for working with the service history table.

Example 14-12 Backing Bean Code for Working with the Service History Table

private CoreTable historyTable;

public void setHistoryTable(CoreTable historyTable) {
  this.historyTable = historyTable;
}

public CoreTable getHistoryTable() {
  return historyTable;
}

When the user selects multiple rows in the service history table, and then clicks the Delete Service History Record button, the tableSelectMany component updates the selection state of the table by placing all the selected rows in a RowKeySet. The backing bean method onDeleteHistoryRows() accesses the binding container, and retrieves the selected keys by calling getSelectionState.getKeySet() on the history table. The backing bean method then executes the deleteServiceHistoryNotes method action binding (which is bound to the deleteServiceHistoryNotes() method in the application module's client interface) by calling the execute() method on the binding. The service method loops through the keySet, deleting the row found by each key. Finally, the backing bean method calls the clear() method on the keySet to remove the keys, after the service method has deleted all the selected rows.

14.7 Setting the Current Object Using a Command Component

There may be cases where you need to programmatically set the current row for an object on an iterator. For example, the SRList page in the SRDemo application uses command links in the second column, as shown in Figure 14-8, which the user can click to directly edit a service request, without needing to first select the row.

Figure 14-8 Command Links Used in a Table on the SRList Page

Command links for the ID set the curent row.

While using command links saves a step for the user, command links do not offer the same functionality as the selection facet, in that they can neither determine nor set the current row on the iterator. Therefore, you must manually set the current row.

14.7.1 How to Manually Set the Current Row

You use the setCurrentRowWithKey or setCurrentRowWithKeyValue built-in operations to set the current row. These operations are built-in methods on any iterator for a collection. The setCurrentRowWithKey operation allows you to set the current row given "stringified" key. The setCurrentRowWithKeyValue operation allows you to set the current row given the a primary key's value. For more information about the current row operations, see Section 10.5.6, "Understanding the Difference Between setCurrentRowWithKey and setCurrentRowWithKeyValue".

While you can drop these operations as any type of command component, the commandLink component is most usually used in this situation. The following procedure explains how to use this component with the setCurrentRowWithKey and setCurrentRowWithKeyValue operations.

To set the current row:

  1. From the Data Control Palette, drag the setCurrentRowWithKey or setCurrentRowWithKeyValue operation.

  2. From the context menu, choose Operations > ADF Command Link.

    JDeveloper creates the command link component on the page, and adds the action binding to the page definition file. You need to change the value for the rowKey parameter in the Action Binding Editor.

  3. Select the command link component in the Structure window, and choose Edit Binding from the context menu.

  4. In the Action Binding Editor, by default, the value for the rowKey parameter is set to ${bindings.setCurrentRowWithKey_rowKey}. The actual value should be something that can be used to determine the current row.

    For example, the command link in Figure 14-8 needs to set the current row to the same row as the link being clicked. To access the "stringified" key of the row for the setCurrentRowWithKey operation, you can use the rowKeyStr property on the binding, or #{row.rowKeyStr}.

    Alternatively, if you use the setCurrentRowWithKeyValue operation, you might set the rowKey to the value of the current row, or #{row.svrId}

    For more information about the variable used to set the current row on a table (in this case, row), see Section 14.2.2.2, "Code on the JSF Page for an ADF Faces Table".

14.7.2 What Happens When You Set the Current Row

When you use the setCurrentRowWithKey operation as a command component, JDeveloper creates an action binding for that operation. Because this operation takes a parameter (rowKey) to determine the current row, it has a NamedData element used to set that value (for more information about parameters and the NamedData element, see Section 17.3, "Creating Command Components to Execute Methods").

Example 14-13 shows the code created in the page definition file when you drop the setCurrentRowWithKey operation and set #{row.rowKeyStr} as the value for the rowKey parameter.

Example 14-13 Page Definition Code for the SetCurrentRowWithKey Operation

<action id="setCurrentRowWithKey" IterBinding="ServiceRequestsByStatusIterator"
            InstanceName="SRService.ServiceRequestsByStatus"
            DataControl="SRService" RequiresUpdateModel="false"
            Action="96">
  <NamedData NDName="rowKey" NDValue="${row.rowKeyStr}"
             NDType="java.lang.String"/>
</action>

14.7.3 What Happens At Runtime

When a user clicks the command link, the setCurrentRowWithKey operation is executed on the iterator, using the rowKey parameter to determine the current row. As with the tableSelectOne component, if you use the same iterator to display the current record, the correct data will display.

Tip:

For functionality similar to that in the SRDemo application, you may need your command link to pass a parameter value that represents the current row. This value might be used by the method used to create the ensuing form. For more information and procedures, see Section 17.4, "Setting Parameter Values Using a Command Component".