Skip Headers
Oracle® Application Development Framework Developer's Guide
10g (10.1.3.1.0)

Part Number B28967-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

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

7.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 7-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 7-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 7-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 7-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 12.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 4.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.

Instead of using the selection facet components to set the current object and then providing a commandButton to navigate to the next page, you can use a commandLink component that allows the user to click a link to both perform an operation on a selection and navigate to another page, which saves the user the step of having to first select a row and then click the command button to perform the action and navigate. However, you must then manually set the current object on the iterator binding. For more information about manually setting the current object, see Section 7.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 set the parameter that represents the selected row for the subsequent page manually. For example, in the SRDemo application, the form on the SREdit page is created using the findServiceRequestById(Integer) method. An Integer that represents the ID for the selected row must be passed to that method in order for the form to properly display. If the parameter is not set, the form displays the first row in the iterator. For more information, see Section 10.4, "Setting Parameter Values Using a Command Component".

7.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 7.6.4, "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 13.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 13.6, "Adding ADF Bindings to Actions". For more information about using methods to create command buttons, see Section 10.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.

7.6.2 What Happens When You Use the TableSelectOne Component

As Example 7-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 7-5 Selection Facet Code

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

As Example 7-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 component to set the selected row as the current object on the iterator.

Example 7-6 Table Selection Attributes

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

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

7.6.4 How to Use the TableSelectMany Component in the Selection Facet

When you add the tableSelectMany component to a table that uses an ADF table binding, you must also add code that sets each selected row in turn to the current object so that the operation can be performed against that object.

To use the tableSelectMany component in an ADF application:

  1. Create the table as shown in Section 7.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 object on top of the af:tableSelectMany node. From the ensuing context menu, choose Methods > Command Button. Doing so drops the method as a command button. You now need to set the parameter value (if needed) for the method. For those procedures, see Section 10.3.1, "How to Create a Command Component Bound to a Service Method".

    For example, if you were working in the SRDemo application and wanted the user to be able to delete the selected rows, you would drag the removeEntity(Object) method onto the af:tableSelectMany node.

    You must now add logic to the method that allows the method to operate against a set of rows, making each row current in turn. To add the logic, you need to override the declarative method created when dropping the command button. For those procedures, see Section 10.5, "Overriding Declarative Methods".

    This code allows you to override the removeEntity(Object) method and add the needed logic.

  5. Add logic to the declarative method that does the following:

    • Accesses the table component

    • Obtains a list of all selected rows

    • Gets the objects in turn and performs the original method on each. To do this, the logic must loop through the list of selected rows as follows:

      • Get a row in the loop

      • Get the key for the row

      • Set it as the current object in the ADF binding

      • Delete the object by calling the declarative method

    Once that is done, logic should be added that refreshes the iterator, so that it displays the correct set of objects. For a code example, see Example 7-10.

7.6.5 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

You then need to override the method and add logic that accesses each selected row in the table and executes the method on that current row.

For example, say you create a table that shows all products using the findAllProduct() method. You then add a tableSelectMany component so that a user can select the products to delete using the removeEntity(Object) method. Example 7-7 shows the code on the JSF page.

Example 7-7 JSF Code for a Table That Uses the tableSelectManyComponent

<af:table value="#{bindings.findAllProducts1.collectionModel}"
                   var="row" rows="#{bindings.findAllProducts1.rangeSize}"
                   first="#{bindings.findAllProducts1.rangeStart}"
                   id="table1">
  <af:column>
     ...
  </af:column>
  <f:facet name="selection">
    <af:tableSelectMany text="Select items and ..."
                        id="tableSelectMany1">
      <af:commandButton text="removeEntity"
                        disabled="#{!bindings.removeEntity.enabled}"
                        id="commandButton1"
                        action="#{backing_MultiDelete.commandButton1_action}"/>
    </af:tableSelectMany>
  </f:facet>
</af:table>

JDeveloper adds code to the page definition that binds the parameter value for the object in the removeEntity(Object) method to the current row of the table, as shown in Example 7-8.

Example 7-8 Method Action Binding for a Method whose Parameter is the Current Row in a Table Binding

<methodAction id="removeEntity" InstanceName="SRPublicFacade.dataProvider"
                  DataControl="SRPublicFacade" MethodName="removeEntity"
                  RequiresUpdateModel="true" Action="999">
  <NamedData NDName="entity"
                 NDValue="${bindings.findAllProducts1.currentRow.dataProvider}"
               NDType="java.lang.Object"/>
</methodAction>
<table id="findAllProducts1" IterBinding="findAllProductsIter">
  <AttrNames>
      ...
  </AttrNames>
</table>

To add logic to a declarative method, you double-click the button in the visual editor, and JDeveloper adds code to the associated backing bean that can access the method logic.

For example, if you drop the removeEntity(Object) method from the SRDemo application into the facet, and then double-click the removeEntity button in the visual editor, JDeveloper adds the code shown in Example 7-9 to the associated backing bean.

Example 7-9 Backing Bean Code for a Declarative Method

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

You then add code that accesses each selected row before the generated code. You use the generated code to execute the method on the object for that row. You then add code after the generated code to reexecute the query and refresh the page.

For example, say you want to allow users to delete rows of products by selecting the products and then deleting them using a command button bound to the removeEntity(Object) method. You would add the declarative code to a backing bean by double-clicking the button. You would then add code shown in bold in Example 7-10 to delete the objects. Code not in bold font is the code generated by JDeveloper, as shown in Example 7-9.

Example 7-10 Complete Backing Bean Code to Allow tableSelectMany

public String commandButton1_action() {

  //Access the tableSelectMany1 table. Note that the table name
  //is taken from the id of the table in the JSF page.
  CoreTable table = this.getTable1();
 
  //Obtain a list of all selected rows from the table
  Set rowSet = table.getSelectionState().getKeySet();
  Iterator rowSetIter = rowSet.iterator();
  
  //Use the declarative method to get the ADF bindings
  BindingContainer bindings = getBindings();
  
  //Get the object to delete. To do this, you must get the
  //iterator binding for the Products in the page definition file,
  //and cast it to DCIteratorBinding for further processing
  DCIteratorBinding pr_dcib = (DCIteratorBinding) 
     bindings.get ("findAllProductsIter");
  
  //Loop through the set of selected row numbers and delete the 
  //equivalent object from the Products collection.
  while (rowSetIter.hasNext()){
    //get the table row
    Key key = (Key) rowSetIter.next();
     
    //set the current row in the ADF binding to the same row
    pr_dcib.setCurrentRowWithKey(key.toStringFormat(true));
    
    //Obtain the Products object to delete
    RowImpl prRow = (RowImpl) pr_dcib.getCurrentRow();
   
   //Delete the object by first accessing the data and then 
   //using the generated code to execute the declarative method
   Products prObjectToDelete = (Products) prRow.getDataProvider();
   OperationBinding operationBinding =
     bindings.getOperationBinding("removeEntity");
     
  //You don't need to set the parameter, as this was done
  //declaritively when you dropped the button on the page
  Object result = operationBinding.execute();
  if (!operationBinding.getErrors().isEmpty())
     return null;
  }     
  
//Re-execute the query to refresh the screen
OperationBinding requery = bindings.getOperationBinding("findAllProducts");
requery.execute();

//Stay on the same page, so no returned outcome needed
return ];
        
}

7.6.6 What Happens at Runtime

When the user selects multiple rows and then clicks the command button, the application accesses the table to determine each of the selected rows, and creates a rowset for those rows. The application then accesses the binding container, and from that container, accesses the iterator used to manage the complete collection and casts it to a generic iterator binding that can manage the rowset of selected rows.

That iterator then goes through each row, and for each row:

  • Sets a key

  • Uses that key to set the row to the current row in the iterator, using the setCurrentRowWithKey operation, as described in Table 6-1, "Built-in Navigation Operations"

  • Uses the current row to create the object against which the method will be executed

  • Accesses the associated data for the object

  • Executes the method

Once that is complete, and there are no more rows in the rowset, the application accesses the iterator in the binding container and reexecutes the query to refresh the set of rows displayed in the table.