4.1 Introduction to Adding Tables

Unlike forms, tables allow you to display more than one data object from a collection returned by an accessor at a time. Figure 4-1 shows a table on the browse page of the Suppliers module, with the products returned from the search.

You can create tables that simply display data, or you can create tables that allow you to edit or create data. Once you drop an accessor as a table, you can add command buttons bound to actions that execute some logic on a selected row. You can also modify the default components to suit your needs.

4.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 components used to display the data in the columns 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.

4.2.1 How to Create a Basic Table

To create a table using a data control, you bind the table component to a returned collection. JDeveloper allows you to do this declaratively by dragging and dropping a collection from the Data Controls panel.

Tip:

You can also create a table by dragging a table component from the Component Palette and completing the Create ADF Faces Table wizard. For more information, see the "How to Display a Table on a Page" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

To create a databound table:

From the Data Controls panel, select a collection.

For example, to create a simple table in the Suppler module that displays products in the system, you would select the productFindAll accessor collection.

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 need your editable table columns to display, and what UI components to use to display the data. By default, ADF inputText components are used for most attributes, thus enabling the table to be editable. Attributes that are dates use the inputDate component. Additionally, if a control type control hint has been created for an attribute, or if the attribute has been configured to be a list, then the component set by the hint is used instead. For more information about setting control hints, see the "Defining Attribute Control Hints for View Objects" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework

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

ADF Read-Only Dynamic Table: Allows you to create a table when the attributes returned and displayed are determined dynamically at runtime. 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.

The ensuing Edit Table Columns dialog shows each attribute in the collection, and allows you to determine how these attributes will behave and appear as columns in your table.

Note:

If the collection contains a structured attribute (an attribute that is neither a Java primitive type nor a collection), the attributes of the structured attributes will also appear in the dialog.

Using this dialog, you can do the following:

Allow the ADF Model layer to handle selection by selecting the Row Selection checkbox. Selecting this option means that the iterator binding will access the iterator to determine the selected row. Select this option unless you do not want the table to allow selection.

Allow the ADF Model layer to handle column sorting by selecting the Sorting checkbox. Selecting this option means that the iterator binding will access the iterator, which will perform an order-by query to determine the order. Select this option unless you do not want to allow column sorting.

Allow the columns in the table to be filtered using entered criteria by selecting the Filtering checkbox. Selecting this option allows the user to enter criteria in text fields above each column. That criteria is then used to build a Query-by-Example (QBE) search on the collection, so that the table will display only the results returned by the query. For more information, see Section 7.5, "Creating Standalone Filtered Search Tables."

Group columns for selected attributes together under a parent column, by selecting the desired attributes (shown as rows in the dialog), and clicking the Group button. Figure 4-2 shows how two grouped columns appear in the visual editor after the table is created.

Figure 4-2 Grouped Columns in an ADF Faces Table

Change the display label for a column by entering text or an EL expression to bind the label value to something else, for example, a key in a resource file. By default, the label is bound to the labels property for any control hint defined for the attribute on the table binding. This binding allows you to change the value of a label text one time in the structure file, and have the change propagate to all pages that display the label.

Change the value binding for a column by selecting a different attribute to bind to. If you simply want to rearrange the columns, you should use the order buttons. If you do change the attribute binding for a column, the label for the column also changes.

Change the UI component used to display an attribute using the dropdown menu. The UI components are set based on the table you selected when you dropped the collection onto the page, on the type of the corresponding attribute (for example, inputDate components are used for attributes that are dates), and on whether or not default components were set as control hints in the Java class's structure file.

Tip:

If one of the attributes for your table is also a primary key, you may want to choose a UI component that will not allow a user to change the value.

Tip:

If you want to use a component that is not listed in the dropdown menu, use this dialog to select the outputText component, and then manually add the other tag to the page.

Change the order of the columns using the order buttons.

Add a column using the Add icon. There's no limit to the number of columns you can add. When you first click the icon, JDeveloper adds a new column line at the bottom of the dialog and populates it with the 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 icon.

Once the table is dropped on the page, you can use the Property Inspector to set other display properties of the table. For example, you may want to set the width of the table to a certain percentage or size. For more information about display properties, see the "Using Tables and Trees" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

Tip:

When you set the table width to 100%, the table will not include borders, so the actual width of the table will be larger. To have the table set to 100% of the container width, expand the Style section of the Property Inspector, select the Box tab, and set the Border Width attribute to 0 pixels.

4.2.2.1 Iterator and Value Bindings for Tables

When you drop a table from the Data Controls panel, a tree value binding is created. A tree consists of a hierarchy of nodes, where each subnode is a branch off a higher level node. In the case of a table, it is a flattened hierarchy, where each attribute (column) is a subnode off the table. Like an attribute binding used in forms, the tree value binding references the accessor iterator binding, while the accessor iterator binding references the iterator for the data control, which facilitates iterating over the data objects in the collection. Instead of creating a separate binding for each attribute, only the tree binding to the table node is created. In the tree binding, the AttrNames element within the nodeDefinition element contains a child element for each attribute that you want to be available for display or reference in each row of the table.

The tree value binding is an instance of the FacesCtrlHierBinding class that extends the core JUCtrlHierBinding class to add two JSF specific properties:

collectionModel: Returns the data wrapped by an object that extends the javax.faces.model.DataModel object that JSF and ADF Faces use for collection-valued components like tables.

Only the table component needs to be bound to the model (as opposed to the columns or the text components within the individual cells), because only the table needs access to the data. The tree binding for the table drills down to the individual structure attributes in the table, and the table columns can then derive their information from the table component.

4.2.2.2 Code on the JSF Page for an ADF Faces Table

When you use the Data Controls panel to drop a table onto a JSF page, 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 another component (such as an inputText or outputText component) bound to the attribute's value. Each column's heading is bound to the labels property for the control hint of the attribute.

Tip:

If an attribute is marked as hidden in the associated structure file, no corresponding UI is created for it.

Example 4-2 shows a simplified code excerpt from a table created by dropping the productFindAll accessor collection as a read-only table.

The tree binding iterates over the data exposed by the iterator binding. Note that the table's value is bound to the collectionModel property, which accesses the collectionModel object. The table wraps the result set from the iterator binding in a collectionModel object. The collectionModel allows each item in the collection to be available within the table component using the var attribute.

In the example, the table iterates over the rows in the current range of the productFindAll accessor binding. This 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.productId}"/>

When you drop an ADF Table (as opposed to an ADF Read-Only Table), instead of being bound to the row variable, the value of the input component is implicitly bound to a specific row in the binding container through the bindings property, as shown in Example 4-3. Additionally, JDeveloper adds validator and converter components for each input component. By using the bindings property, any raised exception can be linked to the corresponding binding object or objects. The controller iterates through all exceptions in the binding container and retrieves the binding object to get the client ID when creating FacesMessage objects. This retrieval allows the table to display errors for specific cells. This strategy is used for all input components, including selection components such as lists.

For more information about using ADF Faces validators and converters, see the "Validating and Converting Input" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

Table 4-1 shows the other attributes defined by default for ADF Faces tables created using the Data Controls panel.

Table 4-1 ADF Faces Table Attributes and Populated Values

Attribute

Description

Default Value

rows

Determines how many rows to display at one time.

An EL expression that, by default, evaluates to the rangeSize property of the associated iterator binding, which determines how many rows of data are fetched from a data control at one time. Note that the value of the rows attribute must be equal to or less than the corresponding iterator's rangeSize value, as the table cannot display more rows than are returned. For more information about the rangeSize property, see Section 3.4.2.2, "Iterator RangeSize Attribute."

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, the attribute displays No data to display when no objects are returned. If the table is not viewable (for example, if there are authorization restrictions set against the table), it displays Access Denied.

fetchSize

Number of rows of data fetched from the data source.

An EL expression that, by default, evaluates to the rangeSize property of the associated iterator binding. For more information about the rangeSize property, see Section 3.4.2.2, "Iterator RangeSize Attribute." This attribute can be set to a larger number than the rows attribute.

selectedRowKeys

The selection state for the table.

An EL expression that, by default, evaluates to the selected row on the collection model.

selectionListener

Reference to a method that listens for a selection event.

An EL expression that, by default, evaluates to the makeCurrent method on the collection model.

rowSelection

Determines whether rows are selectable.

Set to single to allow one row to be selected at a time.

Column Attributes

sortProperty

Determines the property by which to sort the column.

Set to the column's corresponding attribute binding value.

sortable

Determines whether a column can be sorted.

Set to false. When set to true, the iterator binding will access the iterator to determine the order.

headerText

Determines the text displayed at the top of the column.

An EL expression that, by default, evaluates to the label control hint set on the corresponding attribute.

4.2.3 What You May Need to Know About Setting the Current Row in a Table

When you use tables in an application and you allow the ADF Model layer to manage row selection, the current row is determined by the iterator. When a user selects a row in an ADF Faces table, the row in the table is shaded, and the component notifies the iterator of the selected row. To do this, the selectedRowKeys attribute of the table is bound to the collection model's selected row, as shown in Example 4-4.

This binding binds the selected keys in the table to the selected row of the collection model. The selectionListener attribute is then bound to the collection model's makeCurrent property. This binding makes the selected row of the collection the current row of the iterator.

Note:

If you create a custom selection listener, you must create a method binding to the makeCurrent property on the collection model (for example, #{binding.Products.collectionModel.makeCurrent}) and invoke this method binding in the custom selection listener before any custom logic.

Although a table can handle selection automatically, there may be cases where you need to programmatically set the current row for an object on an iterator.

You can call the getKey() method on any view row to get a Key object that encapsulates the one or more key attributes that identify the row. You can also use a Key object to find a view row in a row set using the findByKey(). At runtime, when either the setCurrentRowWithKey or the setCurrentRowWithKeyValue built-in operation is invoked by name by the data binding layer, the findByKey() method is used to find the row based on the value passed in as a parameter before the found row is set as the current row.

The setCurrentRowWithKey and setCurrentRowWithKeyValue operations both expect a parameter named rowKey, but they differ precisely by what each expects that rowKey parameter value to be at runtime:

The setCurrentRowWithKey Operation

setCurrentRowWithKey expects the rowKey parameter value to be the serialized string representation of a view row key. This is a hexadecimal-encoded string that looks like this:

000200000002C20200000002C102000000010000010A5AB7DAD9

The serialized string representation of a key encodes all of the key attributes that might comprise a view row's key in a way that can be conveniently passed as a single value in a browser URL string or form parameter. At runtime, if you inadvertently pass a parameter value that is not a legal serialized string key, you may receive exceptions like oracle.jbo.InvalidParamException or java.io.EOFException as a result. In your web page, you can access the value of the serialized string key of a row by referencing the rowKeyStr property of an ADF control binding (for example. #{bindings.SomeAttrName.rowKeyStr}) or the row variable of an ADF Faces table (for example, #{row.rowKeyStr}).

setCurrentRowWithKeyValue

The setCurrentRowWithKeyValue operation expects the rowKey parameter value to be the literal value representing the key of the view row. For example, its value would be simply "201" to find product number 201.

4.3 Creating an Editable Table

You can create a table that allows the user to edit information within the table, and then commit those changes to the data source. To do this, you use operations that can modify data records associated with the returned collection (or the data control itself) to create command buttons, and place those buttons in a toolbar in the table. For example, the table in the browse.jspx page has a button that allows the user to remove a product. While this button currently causes a dialog to display that allows the user to confirm the removal, the button could be bound to a method that directly removes the product.

As with editable forms, it is important to note that the ADF Model layer is not aware that any row has been changed until a new instance of the collection is presented. Therefore, you need to invoke the execute operation on the accessor iterator in order for any changes to be committed. For more information, see Section 2.3.4, "What You May Need to Know About Iterator Result Caching."

When you decide to use editable components to display your data, you have the option of having the table displaying all rows as editable at once, or having it display all rows as read-only until the user double-clicks within the row. Figure 4-3 shows a table whose rows all have editable fields. The page is rendered using the components that were added to the page (for example, inputText, inputDate, and inputNumberSpinbox components).

Figure 4-3 Table with Editable Fields

Figure 4-2 shows the same table, but configured so that the user must double-click (or single-click if the row is already selected) a row in order to edit or enter data. Note that outputText components are used to display the data in the nonselected rows, even though the same input components as in Figure 4-3 were used to build the page. The only row that actually renders those components is the row selected for editing.

Figure 4-4 Click to Edit a Row

For more information about how ADF Faces table components handle editing, see the "Editing Data in Tables, Trees, and Tree Tables" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

4.3.1 How to Create an Editable Table

To create an editable table, you follow procedures similar to those for creating a basic table, then you add command buttons bound to operations. However, in order for the table to contain a toolbar, you need to add an ADF Faces component that associates the toolbar with the items in the collection used to build the table.

To create an editable table:

From the Data Controls panel, select the collection to display in the table.

For example, to create a simple table in the Suppliers module that will allow you to edit suppliers in the system, you would select the supplierFindAll accessor collection.

Drag the accessor onto a JSF page, and from the context menu, choose ADF Table.

Use the ensuing Edit Table Columns dialog to determine how the attributes should behave and appear as columns in your table. Be sure to select the Row Selection checkbox, which will allow the user to select the row to edit.

With the table selected in the Structure window, expand the Behavior section of the Property Inspector and set the EditingMode attribute. If you want all the rows to be editable select editAll. If you want the user to click into a row to make it editable, select clickToEdit.

From the Structure window, right-click the table component and select Surround With from the context menu.

In the Surround With dialog, ensure that ADF Faces is selected in the dropdown list, select the Panel Collection component, and click OK.

The panelCollection component's toolbar facet will hold the toolbar which, in turn, will hold the command components used to update the data.

This creates a toolbar that already contains a default menu which allows users to change how the table is displayed, and a Detach link that detaches the entire table and displays it such that it occupies the majority of the space in the browser window. For more information about the panelCollection component, see the "Displaying Table Menus, Toolbars, and Status Bars" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

From the Data Controls panel, select the method or operation associated with the collection of objects on which you wish to execute the logic, and drag it onto the toolbar component in the Structure window. This will place the databound command component inside the toolbar.

For example, if you want to be able to remove a supplier record, you would drag the removeSuppliers(Suppliers) method. Figure 4-5 shows the remove methods in the Suppliers module.

Figure 4-5 Operations Associated with a Collection

For the context menu, choose Operations > ADF Toolbar Button.

Because the method takes parameters, the Action Binding Editor opens, asking you to set the value of the parameters.

In the Edit Action Binding dialog, you need to populate the value for the method's parameter. For the remove methods (and the other default methods), this is the selected object.

In the Parameters section, use the Value dropdown list to select Show EL Expression Builder.

In the Expression Builder, expand the node for the accessor's iterator, then expand the currentRow node, and select dataProvider.

This will create an EL expression that evaluates to the data for the current row in the accessor's iterator.

Click OK.

For example, if you created a table using the suppliersFindAll accessor, then JDeveloper would have created an accessorIterator binding named suppliersFindAllIterator. You would need to select the dataProvider object for the current row under that iterator, as shown in Figure 4-8. This reference means that the parameter value will resolve to the value of the currently selected row.

Figure 4-6 dataProvider for the Current Row on the suppliersFindAllIterator Binding

To notify the ADF Model layer that the collection has been modified, you need to also bind the toolbar button to a method that will refresh the iterator.

Open the page definition for the JSPX file by right-clicking the file and choosing Go to Page Definition.

In the Create Action Binding dialog, use the Select an Iterator dropdown list to select the iterator associated with the collection, and for Operation, select Execute.

JDeveloper creates an action binding for the execute operation of the iterator. You now need to have your command button call this operation.

In the JSF page, select the command component created when you dropped the method in Step 10. In the Property Inspector, set Action to the following:

#{bindings.Execute.execute}

When the command component is clicked, the binding to the action attribute is evaluated after the binding for the actionListener attribute. This order ensures iterator refreshes and/or executes after the deletion of entity.

4.4 Creating an Input Table

You can create a table that allows users to insert a new blank row into a table and then add values for each column (any default values set on the corresponding entity object will be automatically populated).

4.4.1 How to Create an Input Table

When you create an input table, you want the user to see the new blank row in the context of the other rows within the current row set. To allow this insertion, you need to use the create operation associated with the accessor for the collection. For example, to create a table that allows users to create new suppliers, you would create a table from the supplierFindAll accessor collection and then add a button using the create operation for the supplierFindAll accessor collection.

Because the create operation only creates a row in the cache, you also need to add a button that actually merges the newly created row into the collection. Figure 4-7 shows how this table might look with a new row created.

Figure 4-7 User Can Create Suppliers in This Input Table

ADF Faces components can be set so that one component refreshes based on an interaction with another component, without the whole page needing to be refreshed. This is known as partial page rendering. When the user clicks the button to create the new row, you want the table to refresh to display that new row. To have that happen, you need to configure the table to respond to that user action.

From the Data Controls panel, drag the create operation associated with the dropped collection and drop it as a toolbar button into the toolbar.

Tip:

You may want to change the ID to something more recognizable, such as Create. This will make it easier to identify when you need to select it as the partial trigger.

In the Structure window, select the table component.

In the Property Inspector, expand the Behavior section, click the dropdown menu for the PartialTriggers attribute, and select Edit.

In the Edit Property dialog, expand the toolbar facet for the panelCollection component and then expand the toolbar that contains the Create command component. Select that component and shuttle it to the Selected panel. Click OK. This sets that component to be the trigger that will cause the table to refresh.

Create a button that allows the user to merge the new object(s) into the collection. From the Data Controls panel, drag the merge method associated with the collection used to create the table, and drop it as a toolbar button or link into the toolbar.

4.4.2 What Happens When You Create an Input Table

When you use the create operation to create an input table, JDeveloper:

Creates an iterator binding for the collection, an action binding for the create operation, and attribute bindings for the table. The create operation is responsible for creating the new row in the row set. If you created command buttons or links using the merge method, JDeveloper also creates an action binding for that method.

Inserts code in the JSF page for the table for the ADF Faces components.

Example 4-5 shows the page definition file for an input table created from the Supplier collection (some attributes were deleted in the Edit Columns dialog when the collection was dropped).

4.4.3 What Happens at Runtime: How Create and Partial Page Refresh Work

When the button bound to the create operation is invoked, the action executes, and a new instance for the collection is created as the page is rerendered. Because the button was configured to be a trigger that causes the table to refresh, the table redraws with the new empty row shown at the top. When the user clicks the button bound to the merge method, the newly created rows in the row set are inserted into the database. For more information about partial page refresh, see the "Rendering Partial Page Content" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

4.4.4 What You May Need to Know About Creating a Row and Sorting Columns

If your table columns allow sorting, and the user has sorted on a column before inserting a new row, then that new row will not be sorted. To have the column sort with the new row, the user must first sort the column opposite to the desired sort, and then re-sort. This is because the table assumes the column is already sorted, so clicking on the desired sort order first will have no effect on the column.

For example, say a user had sorted a column in ascending order, and then added a new row. Initially, that row appears at the top. If the user first clicks to sort the column again in ascending order, the table will not re-sort, as it assumes the column is already in ascending order. The user must first sort on descending order and then ascending order.

If you want the data to automatically sort on a specific column in a specific order after inserting a row, then programmatically queue a SortEvent after the commit, and implement a handler to execute the sort.

4.5 Modifying the Attributes Displayed in the Table

Once you use the Data Controls panel 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, or rebind the table to a new data control.

For more information about modifying existing UI components and bindings, see the "Modifying the Attributes Displayed in the Table" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.

Scripting on this page enhances content navigation, but does not change the content in any way.