Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3) B25386-01 |
|
![]() Previous |
![]() Next |
When the tableSelectOne
component or the tableSelectMany
component is added to the table's selection
facet, the table displays a left most column that allows a user to select one row, or one or more rows, and then take some action on those rows.
The tableSelectOne
component allows the user to select just one row. This component provides a radio button for each row. For example, Figure 7-6 shows the table in the SRList page. The tableSelectOne
component allows a user to select a row and then either view or edit the details for the associated service request.
The tableSelectMany
component displays checkboxes from which the user can select one or more rows. When you use the tableSelectMany
tag, links are added that allow the user to select all or none of the rows. Figure 7-7 shows the table on the SRMain page of the SRDemo application. The tableSelectMany
component allows a user to select multiple records to delete.
Both components have a text
attribute whose value can be instructions for the user. These components 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, "Adding Validation".
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 is ultimately determined by the iterator. The tableSelectOne
component is able to show the current data object determined by the iterator 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.
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 thef indServiceRequestById(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, "Passing Parameter Values to Another Page Using a Command Component".
|
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 included in the selection
facet, along with an Update command button.
Note: You cannot insert atableSelectMany 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".
|
Since you may wish to have the button bound to a method, you need to rebind the Update button to the method of your choice. For rebinding procedures, see Section 13.5, "Adding ADF Bindings to Actions".
You can also manually add a tableSelectOne
component to a table's selection facet.
To manually use the selection facet:
In the Structure window, right-click the table choose Edit Columns.
In the Edit Columns dialog, select Enable Selection and click OK.
JDeveloper adds the tableSelectOne
component (plus the needed listeners and attributes that work with the selection), to the selection facet folder.
In the Structure window, expand the table's selection facet folder and select the tableSelectOne
component.
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.
(Optional): Rebind the Update button to a method of your choice from the Data Control Palette. For rebinding procedures, see Section 13.5, "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 thetext attribute will not display.
|
As Example 7-5 shows, when you elect to use the selection
facet when you first create 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.
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">
Once the user makes a selection and clicks the associated command button, the tableSelectOne
or tableSelectMany
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 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
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.
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:
Create the table as shown in Section 7.2.1, "How to Create a Basic Table" but do not add selection capabilities.
In the Structure window, expand the Table facets folder, right-click the selection facet folder, and choose Insert inside selection > TableSelectMany.
In the Structure window, select the table node and in the Property Inspector, delete the values for the SelectionState and SelectionListener. 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 will create.
From the Data Control Palette, drag the method that will operate on the selected object on top of the tableSelectMany node.
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 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".
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.
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.
When you insert the tableSelectMany
component into a table, and then add a command method bound to a method, JDeveloper does the following:
Adds the tableSelectMany
and command components to the selection facet
Creates a method binding for the bound method, including a NamedData
element used 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 ]; }
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 managed 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.