Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers 10g (10.1.3.1.0) Part Number B25947-01 |
|
|
View PDF |
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.
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.
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.
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 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 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:
In the Structure window, select af:table and choose Edit Columns from the context menu.
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).
In the Structure window, expand the table's selection facet folder and select af:tableSelectOne.
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 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 thetext attribute will not display. |
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}"...>
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.
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 thesetCurrentRowWithKey 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". |
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:
Create the table as shown in Section 14.2.1, "How to Create a Basic Table" but do not select Enable selection.
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 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.
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.
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".
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.
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.
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.