Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g Release 3 (10.1.3.0)

Part Number B25947-02
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

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

18 Creating a Search Form

This chapter describes how to create different types of search pages, for example search forms that work similarly to Oracle Forms EnterQuery/ExecuteQuery searches, or forms that are more like search forms you find on web sites.

This chapter includes the following sections:

18.1 Introduction to Creating Search Forms

You can create a search form that allows users to enter criteria into a form based on known attributes of an object. The criteria is then constructed into a query, and a query-by-example (QBE) search is executed. All records whose attributes match the entered criteria are returned and can then be displayed in a table, either on a separate page or on the same page. To create a QBE search from, you drop a collection from the Data Control palette as an ADF Search Form. When you do this, the input text components do not have any associated validators or converters, which then allows the end user to enter search criteria that might otherwise not pass validation or conversion, such as entering > 1500 into a number field (for more information about conversion and validation, see Chapter 20, "Using Validation and Conversion").

In addition to iterating over collections, an iterator binding provides QBE capability by also being able to iterate over a collection of QBE criteria rows. These rows are created by the criteria entered by the user. Each criteria row has the same attribute structure as a row in its related data collection, except that the attribute values are all treated as a String data type. This data type allows the user to enter in the form fields query criteria containing comparison operators and wildcard characters.

For the iterator binding to have this capability, the binding must be set to Find mode. When an iterator binding is set to work in Find mode, the binding iterates over the these criteria rows instead of the standard collection data. The Execute operation is then used to execute the query against the collection. The Execute operation applies the user's query criteria and also disables the Find mode for the iterator binding, allowing the form to display data returned from the collection, as opposed to criteria. For more information about the Find mode, see Section 10.5.3, "How to Use Find Mode to Implement Query-by-Example".

By default, an ADF Search form contains command buttons bound to the Find and Execute operations. These button are useful if you want to be able to use the form to both search for records and view the current returned record. The user clicks the Find button to put the iterator in Find mode, thus making the input text fields available for criteria. When the user then clicks the Execute button, the criteria is used to create the query, the search is executed, and the form can then display the results. This type of search form is similar to how Oracle Forms EnterQuery/ExecuteQuery searches work. For more information on creating this type of search form, see Section 18.2, "Creating a EnterQuery/ExecuteQuery Search Form".

You can also force the iterator to always be in Find mode, thus negating the need for the Find button and allowing the user to view both their search criteria and the results. The user sees only a button bound to the Execute operation. When the user clicks that button, the iterator is toggled out of Find mode. To have it programatically set back to Find mode so that the user can always enter criteria, you insert an action binding into the page definition file that executes whenever the iterator is not in Find mode (for example after the Execute operation is invoked). However, this means that the results must be displayed in a separate form or table, as the iterator for the search form will always be in Find mode. This type of search is how a typical web page search works. For more information, see Section 18.3, "Creating a Web-type Search Form".

For a this type of web search, you can have the search form and results table on separate pages, or you can have the search form and the results table on the same page. However, when the search and results are on the same page, there must be one iterator that is always in Find mode for the search form, and a separate iterator for the results. See Section 18.3.4, "About Creating Search and Results on the Same Page" for more information. The SRSearch page uses this QBE search functionality, and displays the search form and results table on the same page, as shown in Figure 18-1.

Figure 18-1 Search and Results on the Same Page

Search and results shown on the same page

You can also create a quick search form using named bind variables from a view object created just for the search. For example, the SRStaffSearch page in the SRDemo application uses the StaffListByEmailNameRole view object to create the search form. Instead of dropping the collection as an ADF Search Form, the ExecuteWithParams operation is dropped as a parameter form. When this search is executed, instead of building a QBE query dynamically each time the search is executed, the parameter form uses the view object's design-time SQL statement to execute the query. The text of the SQL statement never changes, so the database can reuse it efficiently, providing increased performance.

By contrast, in a QBE query the WHERE clause predicate is generated dynamically to match your search criteria. So if you keep searching with different combinations of criteria, the text of your SQL statement for that view object changes with the different executions. For example, three different searches might generate the following three different WHERE clauses for their SQL statements:

Because the text of the SQL statement potential changes for a QBE search, the view object creates a new prepared statement each time, and the query must be reparsed on the database side. For this reason, when a search is expected to be frequently executed with the same statement, you may want to use a parameter search form for enhanced performance.

However, in order to create a parameterized search, you create a specific view object for the search. If you need to work programmatically with the rows using their generated custom row interfaces, it might not be practical if the view object for the search requires exactly the same structure and behavior as an existing view object. For example, if you create two view objects, ServiceRequests and ServiceRequestSearch, both with the same structure, and you need to edit the client code to get typesafe access to attributes, you'll need to edit both the ServiceRequestsRow and SearchRequestsSearchRow client interfaces. For this reason, you should use a QBE type search when you the query will require a view object that is the same as an existing view object, and the expected performance savings from a parameterized search will not be great.

In the SRDemo application, the SRSearch page uses a QBE query to find service requests based on the ID, status, problem description, and product name from the ServiceRequests view object. This search page uses an instance of the ServiceRequests view object named SearchServiceRequests, which is instantiated specifically for the search page by the application module. Another instance of the ServiceRequests view object, the ServiceRequestsByStatus instance, is used by the SRList page to show a filtered list of service requests by status.

For more information about view objects, view object instances, and named bind variables, see Chapter 5, "Querying Data Using View Objects"

18.2 Creating a EnterQuery/ExecuteQuery Search Form

You can create a form that allows users to enter search criteria, execute the search, and then review the results of the search in the same form. However, you will need to create two forms that will act as one: one for the search form, and one for the results.

To do this, you set the form used to enter the search criteria to display only when the iterator is in Find mode. You set the second form, which displays the results, to display only when the iterator is not in Find mode. You control the display of each using an EL expression for the Rendered attribute of the forms. This allows the user to enter in a criteria like > 1500 into a number field when the form is in Find mode, but the same entry will raise an error when the user is editing data.

18.2.1 How to Create an EnterQuery/ExecuteQuery Search Page

As stated above, you actually create two forms, one for the query and one for the results. EL expressions are used to determine when to display the correct form.

  1. From the Data Control Palette, drag a collection and from the context menu, select Forms > ADF Search Form.

    For example, if you want the query to execute over all service requests, you would drag the ServiceRequests collection.

  2. Drag the same collection, but this time, drop it as an ADF Form. Select Include Navigation Controls in the Edit Form Fields dialog. This will be the form that displays the results. The navigation controls will allow the user to navigate through the objects returned from the query.

  3. In the Structure window, select the panelForm component for the first form.

  4. In the Property Inspector, in the Rendered field, enter the following expression, replacing <iterator> with the name of the iterator:

    #{bindings.<iterator>.findMode == true}
    

    This will cause the form to be rendered whenever the iterator is in Find mode.

    If you are unsure of the name, you can use the Bind to Data tool to open the Expression Builder, as shown in Figure 18-2.

    Figure 18-2 Clicking to Open the Bind to Data Tool

    Bind To Data tool is in the Property Inspector toolbar

    In the Variables tree of the Expression Builder, select the findMode property under the correct iterator, and click the right arrow to add it to the Expression pane. You then add the logical operator and set the expression to check for true. Figure 18-3 shows the expression that would be built for the ServiceRequestsIterator iterator.

    Figure 18-3 Expression Builder Used to Set the Rendered Attribute

    The Expression Builder has the Rendered attribute selected
  5. In the Structure window, select the panel form for the second form. Set the Rendered property to:

    #{bindings.<iterator_name>.findMode == false}
    

    This expression will cause this form to be displayed whenever the iterator is not in Find mode.

  6. From the Data Control Palette, drag the Find operation associated with the collection and drop it as an ADF Command Button next to the navigation buttons in the second form. This button allows the user to toggle back into Find mode. Doing so will display the first form, so that the user can execute another query.

  7. Rename the Find and Execute buttons to something more meaningful for the user. For example, you might rename the Find button in the top form to Cancel Query, since clicking this button will cause the iterator to toggle out of Find mode. You might rename the Execute button in the top form to Execute Query. Lastly, you might rename the bottom Find button to Enter Query, as that button will be used to place the iterator into Find mode, thereby causing the top form to display.

18.2.2 What Happens When You Create a Search Form

When you drop a search form onto a page, JDeveloper includes a command button bound to the Find operation and a command button bound to the Execute operation, as shown in Example 18-1. The Find operation places the associated iterator into Find mode. The Execute operation executes the query and places the iterator out of Find mode.

Example 18-1 Page Definition Code for Find and Execute Operations

<action id="Find" RequiresUpdateModel="true" Action="3"
            IterBinding="ServiceRequestsIterator"/>
<action id="Execute" RequiresUpdateModel="true" Action="2"
            IterBinding="ServiceRequestsIterator"/>

The following table shows the built-in search operations, along with the result of invoking the operation.

Table 18-1 Search Built-in Operations

Operation Action Attribute Value When invoked, the associated iterator binding will...

Find

3

Places the associated iterator into Find mode, allowing it to iterate over criteria instead of data.

Execute

2

Applies the criteria and executes the query using the criteria from the iterator when in Find mode. Toggles the associated iterator out of Find mode, so that the iterator can work with the results.


Additionally when you drop an ADF Search Form, JDeveloper adds an outputText component inside the panelGroup component that holds the Find and Execute buttons. This outputText component displays the words Find Mode whenever the iterator is in Find mode. This is used mostly for development purposes, allowing you to be able to easily determine when the iterator is in Find mode. You can safely delete this component.

18.3 Creating a Web-type Search Form

For a standard web-type search form, you may not want the user to have to manually place the form into Find mode. Instead, you may want them to simply enter the search criteria and then execute the search. To do this, you configure the iterator so that it is always in Find mode. You can then either have the results displayed on a separate page, or you can display them on the same page. If you have them displayed on the same page, you need to create a separate iterator for the results set that is not continually in Find mode.

18.3.1 How to Create a Search Form and Separate Results Page

To create a search form that is always in find mode, you drop the collection you are searching against as an ADF Search Form, and set a condition on the iterator that keeps it in Find mode. You then drop the same collection as a table or form on another page to display the results.

To create search and results on separate pages:

  1. From the Data Control Palette, drag a collection and from the context menu, select Forms > ADF Search Form.

    For example, if you want the query to execute over all service requests, you would drag the ServiceRequests collection.

  2. On another page, drag the same collection, but this time drop it as any type of table or form.

  3. On the Execute button, create the navigation between the search form and the results page. This will allow the user to navigate to the results page as the query is done. For more information about creating navigation, see Chapter 16, "Adding Page Navigation".

    At this point, when the search form on the page renders, it displays with values in the text boxes from the first record. Users must click the Find button in order to set the iterator into Find mode and enter search criteria. When the user then clicks the Execute button, the user navigates to the results page, whose table displays the results from the query. If the user navigates back to the search form, it displays the attribute values of the first record in the results set.

    You can follow the next set of procedures to eliminate the need for the Find button.

To set the iterator automatically in Find mode:

Follow these steps to automatically put the search form's iterator into Find mode:

  1. Open the page definition file for the search page.

  2. In the Structure Pane, right-click on the Executables node and choose Insert inside executables > invokeAction.

  3. In the Insert invokeAction dialog, enter an ID for the action, such as AlwaysFind. From the Binds drop-down list, select Find. Do NOT click OK or close the dialog.

  4. In the Insert invokeAction dialog, select the Advanced Properties tab.

  5. For Refresh Condition, enter the following EL expression, which tells the application to invoke this Find action whenever the page is not in Find mode. Replace <iterator> with the name of the iterator:

    ${bindings.<iterator>.findMode == false}
    
  6. In the search JSF page, delete the Find button. Doing this only deletes the component from the JSF page. The binding still exists in the page definition because it is being referenced by the EL expression on the RefreshCondition.

18.3.2 What Happens When You Create A Web-type Search Form

When you drop a search form onto a page, JDeveloper includes a command button bound to the Find operation and a command button bound to the Execute operation. For details, see Section 18.2.2, "What Happens When You Create a Search Form".

You use invokeActions to invoke an operation implicitly. For example, in a search page, instead of needing to have the user click the Find button, you can invoke this operation at a defined time or when a defined condition evaluates to true.

The RefreshCondition attribute provides a condition for invoking the action. The Refresh attribute determines at what point in the ADFm lifecycle the action should be invoked, when the RefreshCondition evaluates to true. For a web-type search page, you use an EL expression that evaluates to a condition that says to invoke the Find action whenever the iterator is not in Find mode. For example the page definition for the SRSearch page has the following entries:

Example 18-2 Page Definition Code for a Find InvokeAction and Related Binding

<executables>
  <invokeAction id="AlwaysFind" Binds="Find" Refresh="ifNeeded"
             RefreshCondition=
               "${bindings.SearchServiceRequestsIterator.findMode == false}"/>
  <iterator id="SearchServiceRequestsIterator" RangeSize="10"
            Binds="SearchServiceRequests" DataControl="SRService"/>
</executables>
    ...
<bindings>
    ...  
   <action id="Find" RequiresUpdateModel="true" Action="3"
           IterBinding="SearchServiceRequestsIterator"/>
...
</bindings>

18.3.3 What You May Need to Know

By creating a condition that places the iterator in continuous Find mode, any other binding that references that iterator will also be referencing the iterator when it is in Find mode. Therefore, if you want to have other components on the page that also need to reference that iterator, but do not need it to be in Find mode, you must create a separate iterator based on the same collection. This is how you are able to place the search results on the same page as the search form. See the next section Chapter 18, "About Creating Search and Results on the Same Page" for details.

18.3.4 About Creating Search and Results on the Same Page

As stated above, when you place the iterator into Find mode, it is in Find mode for all associated bindings. When you drop the same collection as a table to display the search results, that table's binding uses the same iterator as the search form. Because that means the table component would be bound to an iterator binding in Find mode, it will display the current query-by-example view criteria rows, as shown in Figure 18-4, instead of the actual data until you hit Execute and the iterator is taken out of Find mode.

Figure 18-4 The Table Displays the Criteria Rows When in Find Mode

Criteria are displayed in the rows of the table

To avoid this, you must create a second iterator for the table that is not in Find mode, but instead displays the collection of data that meets the search criteria.

18.3.5 How To Create Search and Results on the Same Page

To create a page that has both a search form and results table on the same page, you follow the procedures for when they are on separate pages, except you must create a separate iterator for the results table.

To create a search form and results table on the same page:

  1. From the Data Control Palette, drag a collection and from the context menu, select Forms > ADF Search Form.

    For example, if you want the query to execute over all service requests, you would drag the ServiceRequests collection.

  2. Drag the same collection, but this time drop it as any type of table.

  3. Open the associated page definition file.

  4. In the Structure Pane, right-click on the Executables node and choose Insert inside executables > invokeAction.

  5. In the Insert invokeAction dialog, enter an ID for the action, such as AlwaysFind. From the Binds drop-down list, select Find. Do NOT click OK or close the dialog.

  6. In the Insert invokeAction dialog, select the Advanced Properties tab.

  7. For RefreshCondition, enter the following EL expression, which tells the application to invoke this action whenever the page is not in Find mode. Replace <iterator> with the name of the iterator:

    ${bindings.<iterator>.findMode == false} 
    

    Note:

    The invokeAction must appear before the iterator, so that it is executed first.
  8. In the Structure Pane, right-click on the Executables node and choose Insert inside executables > iterator.

  9. Select the same collection used for the search form, and in the Iterator ID field enter a more meaningful name, such as ResultsIterator and click OK.

  10. In the Structure Pane, expand the bindings node, right-click on the binding for the results table, and choose Properties.

  11. In the Table Binding Editor dialog, make sure the correct collection is selected in the Data Collection column.

  12. Select the newly created iterator from the Iterator drop-down list, ensure that all correct attributes are in the Display Attributes column, and click OK.

  13. In the JSF page, delete the Find button.

    Doing this only deletes the component from the JSF page. The binding still exists in the page definition file.

18.3.6 What Happens When Search and Results are on the Same Page

In the above steps, you created a new iterator for the table. This iterator was created using the same collection, however it does not have a find operation associated with it. Therefore, it will always display the results of the search.

For example, the page definition for SRSearch page has the following entries:

Example 18-3 Two Iterators Used to Create a Search Form and Results Table

<executables>   
  <invokeAction id="AlwaysFind" Binds="Find" Refresh="ifNeeded"
                RefreshCondition=
                  "${bindings.SearchServiceRequestsIterator.findMode == false}"/>
...
  <iterator id="SearchServiceRequestsIterator" RangeSize="10"
                Binds="SearchServiceRequests" DataControl="SRService"/>
  <iterator id="SearchServiceRequestsResultsIterator" RangeSize="10"
                Binds="SearchServiceRequests" DataControl="SRService" />
. . .
</executables>
. . .
<bindings>
. . .
  <action id="Find" RequiresUpdateModel="true" Action="3"
            IterBinding="SearchServiceRequestsIterator"
. . .
  <table id="AllServiceRequests" IterBinding="AllServiceRequestsResultsIterator">
   . . .
  </table>
</bindings>

18.4 Creating Search Page Using Named Bind Variables

You can create a search form using a query from a view object that uses named bind variables to find matching objects. For example, the StaffListByEmailNameRole view object uses the following named bind variables:

Figure 18-5 shows the SRStaffSearch search form, created using the StaffListByEmailNameRole view object. This page is used to find a staff user, given a first name, last name, email address, and role.

Figure 18-5 The SRStaffSearch Form

SRStafSearch searches for name, email, and role

18.4.1 How to Create a Parameterized Search Form

Because a parameterized search uses variables that represent parameters, instead of using the Execute operation to invoke the query, you use the ExecuteWithParams operation. You create the search form by dropping ExecuteWithParams operation as a parameterized form. You then drop the corresponding collection as a table a table to display the results. Figure 18-5 shows the ExecuteWithParams operation for the StaffListByEmailNameRole collection.

Figure 18-6 The ExecuteWithParams Operation Uses Parameters

ExecuteWithParams operation has parameters for each variable

To create a search form and results table:

  1. From the Data Control Palette, drag the ExecuteWithParams operation.

  2. From the context menu, choose Parameters > ADF Parameter Form.

  3. Use the Edit Form Fields dialog to change the display of the fields.

  4. From the Data Control Palette, drag the corresponding collection, and drop it as any type of table or form.

18.4.2 What Happens When You Use Parameter Methods

When you drop the ExecuteWithParams operation as a parameter form, JDeveloper:

  • Defines the following in the page definition file: variables to hold the data values, an action binding for the operation, and the attribute bindings for the associated attributes.

  • Inserts code in the JSF page for the form using ADF Faces inputText components bound to the attribute bindings, and an ADF Faces commandButton component bound to the ExecuteWithParams operation. This code is the same as code for any other input form or command button.

Just as when you drop an operation such as Execute or Next, when you drop the ExecuteWithParams operation, JDeveloper creates an action binding. However, because the operation requires parameters to run, JDeveloper also creates NamedData elements for each parameter. These represent the named bind variables on the associated view object. Each NamedData element is bound to a value binding for the corresponding attribute. These bindings allow the operation to access the correct attribute's value for the parameter on execution.

For example, the action binding for the ExecuteWithParams operation on the StaffListByEmailNameRole collection contains a NamedData element for each of the named bind variables on the StaffListByEmailNameRole view object. The EmailAddress NamedData element is bound to the StaffListByEmailNameRole_EmailAddres attribute binding using an EL expression. Example 18-4 shows the action binding and some of the attribute bindings created when you drop the ExecuteWithParameters operation on the StaffListByEmailNameRole collection as a parameter form.

Example 18-4 Method Action Binding in the Page Definition File

<bindings>
  <action id="ExecuteWithParams"
          IterBinding="StaffListByEmailNameRoleIterator"
          InstanceName="SRService.StaffListByEmailNameRole"
          DataControl="SRService" RequiresUpdateModel="true" Action="95">
    <NamedData NDName="EmailAddress" NDType="java.lang.String"
               NDValue="${bindings.StaffListByEmailNameRole_EmailAddress}"/>
    <NamedData NDName="Role" NDType="java.lang.String"
               NDValue="${bindings.StaffListByEmailNameRole_Role}"/>
    <NamedData NDName="TheFirstName" NDType="java.lang.String"
               NDValue="${bindings.StaffListByEmailNameRole_TheFirstName}"/>
    <NamedData NDName="TheLastName" NDType="java.lang.String"
               NDValue="${bindings.StaffListByEmailNameRole_TheLastName}"/>
  </action>
  <attributeValues id="EmailAddress" IterBinding="variables">
    <AttrNames>
      <Item Value="StaffListByEmailNameRole_EmailAddress"/>
    </AttrNames>
  </attributeValues>
...
</bindings>

Because you dropped the ExecuteWithParams operation, the attributes reference a variable iterator that accesses the variables instead of a collection's iterator. This is because the operation (unlike the returned collection) does not need to access an instance of an object; therefore, there is nothing to hold the values entered on the page. Variables act as these data holders.

JDeveloper creates a variable for each named bind variable. The variables are declared as children to the variable iterator, and are local, meaning they live only during a single request, and while they are carried across subsequent post-backs to the same form, they would be forgotten (and re-initialized) when a user navigates to some other page. Example 18-3 shows the variable iterator and variables created when dropping the ExecuteWithParameters operation on the StaffListByEmailNameRole collection. The variable iterator is used both by the form and by the button.

Example 18-5 Variable Iterator and Variables in the Page Definition File

<executables>
  <iterator id="StaffListByEmailNameRoleIterator" RangeSize="10"
            Binds="StaffListByEmailNameRole" DataControl="SRService"/>
  <variableIterator id="variables">
    <variableUsage DataControl="SRService"
                   Binds="StaffListByEmailNameRole.variablesMap.EmailAddress"
                   Name="StaffListByEmailNameRole_EmailAddress"
                   IsQueriable="false"/>
    <variableUsage DataControl="SRService"
                   Binds="StaffListByEmailNameRole.variablesMap.Role"
                   Name="StaffListByEmailNameRole_Role" IsQueriable="false"/>
    <variableUsage DataControl="SRService"
                   Binds="StaffListByEmailNameRole.variablesMap.TheFirstName"
                   Name="StaffListByEmailNameRole_TheFirstName"
                   IsQueriable="false"/>
    <variableUsage DataControl="SRService"
                   Binds="StaffListByEmailNameRole.variablesMap.TheLastName"
                   Name="StaffListByEmailNameRole_TheLastName"
                   IsQueriable="false"/>
  </variableIterator>
</executables>

18.4.3 What Happens at Runtime

When the user enters data and submits the form, the variables are populated and the attribute binding can then provide the value for the named bind variables using the EL expression for the value of the NamedDataElement.

Tip:

When the search form and results table are on the same page, the first time a user accesses the page, the table displays all records from the iterator. You can make it so that the results table does not display until the user actually executes the search. For procedures, see Section 18.5, "Conditionally Displaying the Results Table on a Search Page".

When the user enters Smith as the last name in the corresponding inputText component, and clicks the command button, the following happens:

  • The StaffListByEmailNameRole_TheLastName variable is populated with the value Smith. If no values were entered for the other fields, then the corresponding variables use the default value set for the named bind variables on the view object. For more information, see Section 5.9, "Using Named Bind Variables".

  • Because the attribute binding refers to the variable iterator, the attribute binding can get the value for TheLastName, and any other variable values:

    <attributeValues id="TheLastName" IterBinding="variables">
        <AttrNames>
          <Item Value="StaffListByEmailNameRole_TheLastName"/>
        </AttrNames>
      </attributeValues>
    
  • Because the NamedData element has an EL expression that evaluates to the item value of the attribute binding, the parameter can also access the value:

    <NamedData NDName="TheLastName" NDType="java.lang.String"
        NDValue="${bindings.StaffListByEmailNameRole_TheLastName}"/>
    
  • The ExecuteWithParams operation is executed with the parameters taking their values from the NamedData elements.

  • The operation applies the named bind variable values and executes the query.

  • The StaffListByEmailNameRoleIterator iterator iterates over the collection, allowing a table to display the results. For more information about tables at runtime, see Section 14.2.2, "What Happens When You Use the Data Control Palette to Create a Table".

18.5 Conditionally Displaying the Results Table on a Search Page

When a web search form and results table are on the same page, the first time a user accesses the page, the table displays all records in the current range from the iterator. You can make it so that the results table does not display until the user actually executes the search. Figure 18-7 shows the SRSearch page as it displays the first time a user accesses it.

Figure 18-7 Hidden Results Table for a Search Page

The results table does not display in the SRSearch page

Once the user executes a search, the results table displays, as shown in Figure 18-8.

Figure 18-8 Results Table Displayed for a Search Page

The results table displays once a search is executed.

18.5.1 How to Add Conditional Display Capabilities

To conditionally display the results table, you must enter an EL expression on the UI component (either the table itself or another component that holds the table component), that evaluates to whether this is the first time the user has accessed the search page. A field on a managed bean holds the value used in the expression.

To conditionally display the results table:

  1. Create a search form and results table on the same page.

  2. Create a flag on a managed bean that will be set when the user accesses the page for the first time. For example, the userState managed bean in the SRDemo application contains the SEARCH_FIRSTTIME_FLAG parameter. An EL expression on the page needs to know the value of this parameter to determine whether or not to render the results table (see step 4). When the bean is instantiated for the EL expression, the isSearchFirstTime method then checks that field. If it is null, it sets the value to True. For information about creating managed beans, see Section 17.2, "Using a Managed Bean to Store Information"

  3. On the JSF page, insert a setActionListener component into the command component used to execute this search. Set the from attribute to #{false}. Set the to attribute to the field on the managed bean created in step two. This will set that field to false whenever the button is clicked. For more information about using the setActionListener component, see Section 17.4, "Setting Parameter Values Using a Command Component".

    Example 18-3 shows the code for the Search button on the SRSearch page.

    Example 18-6 Using a setActionListener Component to Set a Value

    <af:commandButton actionListener="#{bindings.Execute.execute}"
                     text="#{res['srsearch.searchLabel']}">
      <af:setActionListener from="#{false}"
                               to="#{userState.searchFirstTime}"/>
    </af:commandButton>
    
  4. On the JSF page, use an EL expression as the value of the Rendered attribute so that the UI component (the table or the UI component holding the table) only renders when the variable is a certain value.

    Example 18-5 shows the EL expression used for the value for the Rendered attribute of the panelGroup component on the SRSearch page.

    Example 18-7 JSF Code to Conditionally Display the Search Results Table

    <af:panelGroup rendered="#{userState.searchFirstTime == false}">
    

    This EL expression causes the panelGroup component to render only if the searchFirstTime flag has a value of False.

18.5.2 What Happens When you Conditionally Display the Results Table

When you use a managed bean to hold a value, other objects can both set the value and access the value. For example, similar to passing parameter values, you can use the setActionListener component to set values on a managed bean that can then be accessed by an EL expression on the rendered attribute of a component.

For example, when a user accesses the SRSearch page for the first time, the following happens:

  • Because the panelGroup component that holds the table contains an EL expression for it's rendered attribute, and the EL expression references the userState bean, that bean is instantiated.

  • Because the user has not accessed page, the SEARCH_FIRSTTIME_FLAG field on the userState bean has not yet been set, and therefore has a value of null

  • Because the value is null, the isSearchFirstTime method on that bean sets the SEARCH_FIRSTTIME_FLAG field to true.

  • When the EL expression for the panelGroup component is evaluated, because he SEARCH_FIRSTTIME_FLAG field is true, the SRSearch page displays without rendering the panelGroup component. This is because the EL expression for the Rendered attribute evaluates to True only when SEARCH_FIRSTTIME_FLAG field is false.

  • When the user enters search criteria and clicks the Search button, the associated setActionListener component sets the SEARCH_FIRSTTIME_FLAG field on the userState bean to false.

  • Because there is no outcome defined for the command button, the user stays on the same page.

  • Because the SEARCH_FIRSTTIME_FLAG field is now set to false, when the page rerenders with the results, the panelGroup component displays the table with the result.