Data binding is the process that ties data to presentation tags in JSPs, thereby creating dynamic web applications that are easy to build and maintain. This topic describes the NetUI Data Binding tags that are used to display large(r) data sets.
<%@ taglib uri="netui-tags-databinding.tld" prefix="netui-data"%>
When you add a NetUI Data Binding component to your JSP, you will notice that the component name is prefixed with "netui-data", for example:
<netui-data:grid dataSource="{pageFlow.allRows}" name="{pageFlow.gridName}">
...
</netui-data:grid>
The NetUI Data Binding tags fall into one of the following categories:
The functionality of the various tags are described below. For a detailed description of a tag including its attributes, see JSP Tags Reference, or in Source View, place your cursor inside the tag and press F1.
Note: The netui-data:getData tag, used to bind data to a JSP's page context, is discussed in Using Data Binding in Page Flows. For information on the netui-data:message and netui-data:messageArg tags, see How Do I: Customize Message Formats in Page Flows?
The method invocation tags netui-data:callControl and netui-data:callPageFlow are used to invoke methods on Controls or PageFlowController instances. The former tag allows access to controls directly from a JSP, while the latter allows controller methods to be called directly from the JSP. While Page Flow actions are not meant to be invoked with the netui-data:callPageFlow tag, calling JPF code from the JSP is useful for localizing code, which is used in many different pages, in a single location.
The tags in the repeater tag set are used to render data sets into a JSP page. A reapeater tag is a tag that, given a data set, renders each item or a subset of items in the data set into a page. Let's take a look at an example:
<netui-data:repeater dataSource="{pageFlow.strArr}">
<netui-data:repeaterHeader>
<ul>
</netui-data:repeaterHeader>
<netui-data:repeaterItem>
<li>
<netui:label
value="{container.item}" />
</li>
</netui-data:repeaterItem>
<netui-data:repeaterFooter>
</ul>
</netui-data:repeaterFooter>
</netui-data:repeater>
The top level tag is netuid-data:repeater, which binds to the complex data set. In the example the complex data set is an array of Strings, which was added to the page flow. The netui-data:repeaterHeader and netui-data:repeaterFooter tags are not repeated but appear only once as the header and the footer. In the example these are used to start and end a bulleted list. The netui-data:repeaterItem contains the code that is repeated. Typically it will contains some html formatting code - in the example <li> and </li> - plus a netui tag that binds to each item in the dataset using the container data binding context. The example will generate a bulleted list with each item in the String array displayed as a separate bullet.
Notice that the repeater tags use tags from the other tag libraries to create formatted data. This is how you ensure that data is displayed in a meaningful way to the user. Another example of netui-data:repeater, which uses a table to format the data, is shown next:
<netui-data:repeater dataSource="{pageContext.vec}">
<netui-data:repeaterHeader>
<table border="1">
<tr>
<td><b>index</b></td>
<td><b>name</b></td>
</tr>
</netui-data:repeaterHeader>
<netui-data:repeaterItem>
<tr>
<td>
<netui:label
value="{container.index}" />
</td>
<td>
<netui:label
value="{container.item}" />
</td>
</tr>
</netui-data:repeaterItem>
<netui-data:repeaterFooter>
</table>
</netui-data:repeaterFooter>
</netui-data:repeater>
The previous two examples showed read-only examples of displaying complex data. However, it is also possible to display complex data in a form and allow the user to change the data. For example, to display a String array and allow the user to change the values, you can use this code:
<netui:form action="submit">
<netui-data:repeater dataSource="{pageFlow.strArr}">
<netui-data:repeaterHeader>
<ul>
</netui-data:repeaterHeader>
<netui-data:repeaterItem>
<li>
<netui:textBox
dataSource="{actionForm.name}" defaultValue="{container.item}"
/>
</li>
</netui-data:repeaterItem>
<netui-data:repeaterFooter>
</ul>
</netui-data:repeaterFooter>
</netui-data:repeater>
<netui:button type="submit" value="submit"></netui:button>
</netui:form>
This example will display a bulleted list of strings, with each string in a separate form field. Notice that the netui:textBox receives its default value from the container context and uses the form bean's name property to submit the value. The form bean variable will have to be a String array:
public static class SubmitForm extends FormData
{
private java.lang.String[] name;
...
You can easily create a variable array for a form bean in Action View or Flow View by selecting the array checkbox for a form bean variable in the Edit Form Bean dialog. The necessary getter and setter methods to enable read-write access will then be automatically created for you.
In the action method that is called when submitting the form, you can use standard Java array notation to access the individual elements:
/**
* @jpf:action
* @jpf:forward name="success" path="submitPage1.jsp"
*/
protected Forward submit(SubmitForm form)
{
System.out.println(form.name[1]);
...
return new Forward("success");
}
In the above example, instead of using a form bean to hold the submitted values, we could have used the same String array that we read from to write the values to upon submit. This would require changing the netui:textBox tag in the above JSP code as is shown next:
<netui:form action="submit">
<netui-data:repeater dataSource="{pageFlow.strArr}">
...
<netui-data:repeaterItem>
<li>
<netui:textBox
dataSource="{container.item}" />
</li>
</netui-data:repeaterItem>
...
</netui-data:repeater>
<netui:button type="submit" value="submit"></netui:button>
</netui:form>
Notice that the String array is stored in the pageFlow context, so you can access it accordingly in the action method:
/** * @jpf:action * @jpf:forward name="success" path="submitPage1.jsp" */ protected Forward submit() { System.out.println(strArr[1]); return new Forward("success"); }
You can use nested <netui-data:repeater> tags to render a multi-dimensional array.
Suppose you have the following multi-dimensional array.
String[][] multiDimArr = { {"1","2","3","4","5"}, {"a","b","c","d","e"}, {"!","@","#","$","%"}, {"A","B","C","D","E"} };
You can use one <netui-data:repeater> tag nested inside another to iterate over every element in the multi-dimensional array.
The outer <netui-data:repeater> tag iterates over the outer array.
<table border="1"> <netui-data:repeater dataSource="{pageContext.multiDimArr}"> ... </netui-data:repeater> </table>
The inner <netui-data:repeater> tag iterates over the elements of the inner arrays.
<table border="1"> <netui-data:repeater dataSource="{pageContext.multiDimArr}"> <tr> <netui-data:repeater dataSource="{container.item}"> <td><netui:label value="{container.item}" /></td> </netui-data:repeater> </tr> </netui-data:repeater> </table>
Notice that the two data binding expressions {container.item} are not synonymous.
The first occurance of {container.item} refers to the elements of the outer array, for example, {"1", "2", "3", "4", "5"}, {"a","b","c","d","e"}, etc. The second occurance of {container.item} refers to the elements of the current inner array, for example, "1", "a", "!", etc. The result is the following HTML table.
<table border="1"> <tr> <td>1</td> <td>2</td> <td>3</td> <td>4</td> <td>5</td> </tr> <tr> <td>a</td> <td>b</td> <td>c</td> <td>d</td> <td>e</td> </tr> <tr> <td>!</td> <td>@</td> <td>#</td> <td>$</td> <td>%</td> </tr> <tr> <td>A</td> <td>B</td> <td>C</td> <td>D</td> <td>E</td> </tr> </table>
In the browser the table appears as follows.
1 | 2 | 3 | 4 | 5 |
a | b | c | d | e |
! | @ | # | $ | % |
A | B | C | D | E |
The Repeater also provides more advanced features to customize how the items in the data set are displayed, in particular by using padding and choice.
Padding is used in the repeater to create a regular display of an irregular data set. The netui-data:pad tag provides attributes such as maxRepeat, minRepeat, and padText that controls how many container items are displayed, and what to display instead if there are less items than expected. For more information, see the netui:pad reference documentation.
The choice feature is used to create a different display for an item depending on its value. This functionality is implemented using two tags, namely netui-data:choiceMethod and netui-data:choice. The former method is used to indicate the item that is being considered, while the latter method defines a possible value for this item and the display to be rendered when this value is found. Both tags must occur within a netui-data:repeaterItem tag.
Also, the related netui-data:methodParameter tag is embedded within the netui-data:choiceMethod tag, as shown in the following example. You can use the netui-data:methodParameter tag to get the value that will be used by the choice tags.
<netui-data:repeater dataSource="{pageFlow.cart.lineItemList}">
<netui-data:repeaterHeader>
...
</netui-data:repeaterHeader>
<netui-data:repeaterItem>
<netui-data:choiceMethod
object="{pageFlow}" method="getShippingState">
<netui-data:methodParameter
value="{container.item.shipState}"/>
</netui-data:choiceMethod>
<netui-data:choice value="inTransit">
...
<netui-html:label
value="{container.item.name}"/>
<netui-html:label
value="In Transit"/>
...
</netui-data:choice>
<netui-data:choice value="arrived">
...
<netui-html:label
value="{container.item.name}"/>
<netui-html:label
value="Arrived"/>
...
</netui-data:choice>
<netui-data:choice value="notShipped">
...
<netui-html:label
value="{container.item.name}"/>
<netui-html:label
value="Not Yet Shipped"/>
...
</netui-data:choice>
<netui-data:choice default="true">
...
<netui-html:label
value="{container.item.name}"/>
<netui-html:label
value="Error;status unknown./>
...
</netui-data:choice>
</netui-data:repeaterItem>
<netui-data:repeaterFooter>
...
</netui-data:repeaterFooter>
</netui-data:repeater>
In the example, the netui-data:choiceMethod tag indicates that the item's shipState must be used to decide which formatting to display. Specifically, its method attribute specifies the method getShippingState, which is a method that is defined in the pageFlow context object, as is indicated in the tag's object attribute. This method getShippingState takes a single argument, the current item's shipState, as is defined in the nested netui-data:methodParameter tag. The various netui-data:choice tags implement what to display given the return value of the getShippingState method for the current item, that is, inTransit, arrived, notShipped, or any other value using the default choice tag. Notice that in the current example some html formatting tags were removed for the sake of clarity. However, you can add html tags to each netui-data:choice tag to render different formatting, for instance to display error values in red, expected values in green, and so forth.
The previous example uses a number of possible static values for the netui-data:choice tag. However, it is also possible to bind its value attribute, as is shown in the following example:
<netui-data:repeater dataSource="{pageFlow.cart.lineItemList}">
<netui-data:repeaterHeader>
...
</netui-data:repeaterHeader>
<netui-data:repeaterItem>
<netui-data:choiceMethod
object="{pageFlow}" method="getSpecialItems">
<netui-data:methodParameter
value="{container.item.name}"/>
</netui-data:choiceMethod>
<netui-data:choice value="{container.item.name}">
...
<netui-html:label
value="{container.item.name}"/>
<netui-html:label
value="Special"/>
...
</netui-data:choice>
<netui-data:choice default="true">
...
<netui-html:label
value="{container.item.name}"/>
...
</netui-data:choice>
</netui-data:repeaterItem>
<netui-data:repeaterFooter>
...
</netui-data:repeaterFooter>
</netui-data:repeater>
In the example a new method getSpecialItems, referenced in the netui-data:choiceMethod tag, is used to evaluate each item's name, and it returns the name for special items only (depending on some business logic). The first netui-data:choice tag's value attribute in the example binds to the current item's name, so for special items this value will match the return value of the method, and the formatting defined in this choice tag will be used. All other items will be formatted as defined in the default choice tag.
The netui-data:cellRepeater is like the netui-data:Repeater tag in that it is used to display each item in a complex data set. The difference is that the netui-data:cellRepeater displays each item in the cell of a table. All the html tags necessary to create the table are automatically created by the cellRepeater tag. For example:
<netui-data:cellRepeater dataSource="{pageFlow.itemArray}"
columns="{pageFlow.numColumns}" >
Item: <netui:label value="{container.item}"/>
</netui-data:cellRepeater>
This example creates a table with a certain number of columns as given in pageFlow.numColumns and as many rows as necessary to display all the items in the data set. Each cell in the table will contain Item: 'the actual item'. The cellRepeater tag has other attributes to determine the formatting of the table and the individual cells. For more information, see the reference documentation for this tag.
A final repeating databinding tag set is the Grid tag set, which is used to render data from a javax.sql.RowSet object. A RowSet object is used to hold a typically disconnected data set that contains data from a relational database (for more information, see its API reference at http://java.sun.com). The Grid tag set provides the ability to display, page, sort, and filter data. The Grid tag does not display items using standard html formatting tags, and does not use the container data binding context (except for the tag netui-data:expressionColumn). Instead the grid uses specific grid tags to enable table-like formatting and to accomplish data binding, assuming that the same number of columns are rendered for each row in the table.
In WebLogic Workshop you can easily generate a page flow that uses grid tags to display the records in a relational database and contains the action methods to update, insert and delete records. For more information, see How Do I: Create a Database Control Page Flow?
Let's take a look at an example to understand the various grid tags (to see and run the entire example, go to the databasePageFlowController.jpf Sample):
<netui-data:grid dataSource="{pageFlow.allRows}"
name="{pageFlow.gridName}">
<netui-data:gridStyle styleClassPrefix="gridStyle"/>
<netui-data:pager renderInHeader="true"
action="begin" renderInFooter="true"/>
<netui-data:columns filterable="true"
filterAction="begin" sortAction="begin" sortable="true">
<netui-data:anchorColumn
action="getItems" addRowId="true" title="Details"/>
<netui-data:anchorColumn
action="updateItems" addRowId="true" title="Edit"/>
<netui-data:basicColumn
title="Itemnumber" name="itemnumber"/>
<netui-data:basicColumn
title="Itemname" name="itemname"/>
<netui-data:basicColumn
title="Quantityavailable" name="quantityavailable"/>
<netui-data:basicColumn
title="Price" name="price"/>
</netui-data:columns>
</netui-data:grid>
The following tags are used in the example:
If the title and name attributes are both specified, the header will have the title name and the cells in the column will be filled with the values of a record field as specified in the name attribute. In our example, the first basicColumn has a header named Itemnumber, followed by cells which display the contents of the record field itemnumber in the RowSet. In addition, when both name and title are specified, you can optionally sort the data by value in this column (the default is sortable in ascending order). To sort data by column, you click the linked header for this column (in our example, Itemnumber will appear linked). Finally, when both name and title attributes are specified, you can also optionally filter the data (the default is true). If filtering is enabled for a column, a filter icon will appear to the right of the header name. When you click this item, a dialog appears with a large number of filtering options. If the filter icon appears in blue, then the values in this columns are filtered. You can enable filtering in multiple columns at the same time.
Note: When you filter the data on a column, a new SQL query is generated that is run by the page flow, and the matching records are returned to the RowSet object.
In addition to the tags used in the example, there are several additional tags:
<netui-data:columns filterable="true" filterAction="begin"
sortAction="begin" sortable="true">
<netui-data:anchorColumn action="getItems"
addRowId="true" title="Details"/>
...
<netui-data:expressionColumn title="Itemname,
Itemnumber" value=
'name=<b>{container.item.itemname}</b>
<br>number=<i>{container.item["itemnumber"]}<i/>'/>
</netui-data:columns>
When you select the Grid icon from the Palette window and drag and drop this onto your JSP's Design View or Source View, a dialog will assist you in setting up the grid tag table. You can select the data source, whether to use a Pager (that is, define a netui-data:pager tag), the number of data columns (with netui-data:basicColumn tags), and an anchor column (that is, define a netui-data:anchorColumn tag) that you can make filterable and/or sortable. After clicking OK, go to Source View to associate each column with the corresponding record field in your data source through the column's name attribute.
Using Data Binding in Page Flows
Using Form Beans to Encapsulate Data
Designing User Interfaces in JSPs
How Do I: Customize Message Formats in Page Flows?
How Do I: Create a Database Control Page Flow?