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

17 Creating More Complex Pages

This chapter describes how to add more complex bindings to your pages, such as using methods that take parameters to create forms and command components.

This chapter includes the following sections:

17.1 Introduction to More Complex Pages

Once you create a basic page and add navigation capabilities, you may want to add more complex features to your pages, such as the ability to store information on a managed bean, or the ability to override declarative actions. ADF provides many features that allow you to add this complex functionality using very little actual code.

For example, the Delete button on the SRMain page was created by dragging the Delete operation for the ServiceRequest collection and dropping it as a command button. Then that Delete operation was overridden, so that when the button is clicked, it not only deletes the service request from the cache, but also commits the transaction. Additionally, the SRMain page can be accessed from a number of pages in the SRDemo application. The userState managed bean (UserSystemState.java) holds the value of the originating page. The overridden Delete operation also contains logic to access the value of the originating page so that the user navigates successfully off the SRMain page.

Read this chapter to understand:

17.2 Using a Managed Bean to Store Information

Often, pages require information from other pages. Instead of setting this information directly on a page (for example, by setting the parameter value on the page's page definition file), which essentially hardcodes the information, you can store this information on a managed bean. As long as the bean is stored in a scope that is accessible, any value for an attribute on the bean can be accessed using an EL expression.

Tip:

Use managed beans to store only "bookeeping" information. All application data and processing should be handled by logic in the business layer of the application.

For example, the SRMain page needs to know the page from which the user navigated from in order to return the user to the correct page. The SRDemo application has a managed bean that holds this information, allowing the sending page to set the information, and the SRMain page to use the information in order to determine where to navigate.

Managed beans are Java classes that you register with the application using the faces-config.xml file. When the JSF application starts up, it parses this configuration file and the beans are made available and can be referenced in an EL expression, allowing access to the beans' properties and methods. Whenever a managed bean is referenced for the first time and it does not already exist, the Managed Bean Creation Facility instantiates the bean by calling the default constructor method on the bean. If any properties are also declared, they are populated with the declared default values.

17.2.1 How to Use a Managed Bean to Store Information

Using the JSF Configuration Editor in JDeveloper, you can create a managed bean and register it with the JSF application at the same time.

To create a managed bean:

  1. Open the faces-config.xml file. This file is stored in the <project_name>/WEB-INF directory.

  2. At the bottom of the window, select the Overview tab.

  3. In the element list on the left, select Managed Beans. Figure 17-1 shows the JSF Configuration Editor for the faces-config.xml file.

    Figure 17-1 The JSF Configuration Editor

    The JSF Configuration Editor shows all the managed beans
  4. Click the New button to open the Create Managed Bean dialog, as shown in Figure 17-2. Enter the name and fully qualified class path for the bean. Select a scope, select the Generate Java File checkbox, and click OK.

    Figure 17-2 The Create Managed Bean Dialog

    Fields to enter name, class, and scope

    Tip:

    If the managed bean will be used by multiple pages in the application, you should set the scope to Session. However, then the bean cannot contain any reference to the binding container, as the data on the binding object is on the request scope, and therefore cannot "live" beyond a request. For examples of when you may need to reference the binding container, see Section 17.5, "Overriding Declarative Methods".
  5. You can optionally use the arrow to the left of the Managed Properties bar to display the properties for the bean. Click New to create any properties. Press F1 for additional help with the configuration editor.

    Note:

    While you can declare managed properties using the configuration editor, the corresponding code is not generated on the Java class. You will need to add that code by creating private member fields of the appropriate type and then using the Generate Accessors... menu item on the context menu of the code editor to generate the corresponding getter and setter methods for these bean properties.

17.2.2 What Happens When You Create a Managed Bean

When you use the configuration editor to create a managed bean, and elect to generate the Java file, JDeveloper creates a stub class with the given name and a default constructor. Example 17-1 shows the code added to the MyBean class stored in the view package.

Example 17-1 Generated Code for a Managed Bean

package view;
 
public class MyBean {
    public MyBean() {
    }
}

JDeveloper also adds a managed-bean element to the faces-config.xml file. This declaration allows you to easily access any logic on the bean using an EL expression that refers to the given name. Example 17-2 shows the managed-bean element created for the MyBean class.

Example 17-2 Managed Bean Configuration on the faces-config.xml File

<managed-bean>
  <managed-bean-name>my_bean</managed-bean-name>
  <managed-bean-class>view.MyBean</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

You now need to add the logic required by your pages and methods in your application. You can then refer to that logic using an EL expression that refers to the managed-bean-name given to the managed bean. For example, to access the myInfo property on the bean, the EL expression would be:

#{my_bean.myInfo}

The following sections of this chapter provide examples of using the SRDemo application's userState managed bean (view.UserSystemState.java) to hold or get information. Please see those sections for more detailed examples of using a managed bean to hold information.

17.3 Creating Command Components to Execute Methods

When your application contains custom methods, these methods appear in the Data Control Palette. You can then drag these methods and drop them as command buttons. When a user clicks the button, the method is executed. For more information about custom methods, see Chapter 8, "Implementing Business Services with Application Modules".

For example, the SRService application module in the SRDemo application contains the deleteServiceHistoryNotes(Set keySet) method. This method ensures that one or more rows are selected, then deletes those rows and commits the transaction. To allow the user to execute this method, you drag the deleteServicehistoryNotes(Set) method from the Data Control Palette, as shown in Figure 17-3.

Figure 17-3 Methods in the Data Control Palette

deleteServiceHistoryNotes in the DCP takes the Set parameter

Note:

In the SRDemo application, additional view-layer logic is added to the deleteServiceHistoryNotes(Set) method by overriding this method in a managed bean. You can also override a custom method if you need to provide conditional navigational logic. For more information, see Section 17.5, "Overriding Declarative Methods".

17.3.1 How to Create a Command Component Bound to a Service Method

In order to perform the required business logic, many methods require a value for the method's parameter or parameters. That means when you create a button bound to the method, you need to specify from where the value for the parameter(s) can be retrieved.

For example, if you use the deleteServicehistoryNotes(Set) method, you need to specify the set of rows to be deleted.

To add a button bound to a method:

  1. From the Data Control Palette, drag the method onto the page.

    Tip:

    If you are dropping a button for a method that needs to work with data in a table or form, that button must be dropped inside the table or form.
  2. From the context menu, choose Methods > ADF Command Button.

  3. If the method takes parameters, the Action Binding dialog opens. In the Action Binding Editor, click the ellipses (...) button in the Value column of Parameters to launch the EL Expression Builder. You use the builder to set the value of the method's parameter.

17.3.2 What Happens When You Create Command Components Using a Method

When you drop a method as a command button, JDeveloper:

  • Defines a method action binding for the method. If the method takes any parameters, JDeveloper creates NamedData elements that hold the parameter values.

  • Inserts code in the JSF page for the ADF Faces command component. This code is the same as code for any other command button, as described in Section 13.4.2.3, "Using EL Expressions to Bind to Navigation Operations". However, instead of being bound to the execute method of the action binding for a built-in operation, the button is bound to the execute method of the method action binding for the method that was dropped.

17.3.2.1 Using Parameters in a Method

When you drop a method that takes parameters onto a JSF page, JDeveloper creates a method action binding. This binding is what causes the method to be executed when a user clicks the command component. When the method requires parameters to run, JDeveloper also creates NamedData elements for each parameter. These elements represent the parameters of the method.

For example, the deleteServiceHistoryNotes method action binding contains a NamedData element for the Set parameter. This element is bound to the value specified when you created the action binding. Example 17-3 shows the method action binding created when you drop the deleteServiceHistoryNotes(Set) method, and bind the Set parameter (named keySet) to the keySet property of the selectionState property of the history table UI component in the page's backing bean (for more information about using this method to delete multiple rows (the key set), see Section 14.6.5, "How to Use the TableSelectMany Component in the Selection Facet").

Example 17-3 Method Action Binding for a Parameter Method

<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>

17.3.2.2 Using EL Expressions to Bind to Methods

Like creating command buttons using operations, when you create a command button using a 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. This binding causes the binding's method to be invoked on the application module. For more information about the command button's actionListener attribute, see Section 13.4.3, "What Happens at Runtime: About Action Events and Action Listeners".

Tip:

Instead of binding a button to the execute method on the action binding, you can bind the button to method in a backing bean that overrides the execute method. Doing so allows you to add logic before or after the original method runs. For more information, see Section 17.5, "Overriding Declarative Methods".

Like navigation operations, the disabled property on the button uses an EL expression to determine whether or not to display the button. Example 17-4 shows the EL expression used to bind the command button to the deleteServiceHistoryNotes(Set) method.

Example 17-4 JSF Code to Bind a Command Button to a Method

<af:commandButton actionListener="#{bindings.deleteServiceHistoryNotes.execute}"
                  text="deleteServiceHistoryNotes"
                  disabled="#{!bindings.deleteServiceHistoryNotes.enabled}"/>

Tip:

When you drop a UI component onto the page, JDeveloper automatically gives it an ID based on the number of that component previously dropped, for example, commandButton1, commandButton2. You may want to change the ID to something more descriptive, especially if you will need to refer to it in a backing bean that contains methods for multiple UI components on the page. Note that if you do change the ID, you must manually update any references to it in EL expressions in the page.

17.3.3 What Happens at Runtime

When the user clicks the button, the method binding causes the associated method to be invoked, passing in the value bound to the NamedData element as the parameter. For example, if a user clicks a button bound to the deleteServiceHistoryNotes(Set) method, the method takes the value of the key set (in this case the selected rows in a table) and deletes them from the data source.

17.4 Setting Parameter Values Using a Command Component

There may be cases where an action on one page needs to set parameters that will be used to determine application functionality. For example, the results table on the SRSearch page will display only if the value of the searchFirstTime flag on the userState managed bean is false. When this bean is instantiated as the search page is rendered, the isSearchFirstTime method on the bean checks that parameter. If it is null (which it will be the first time the page is rendered), the bean sets the value to true.

A setActionListener component, which is nested in the command button used to execute this search, is then used to set the searchFirstTime flag to false, thus causing the results table to display once the search is executed. For information about using managed beans, see Section 17.2.1, "How to Use a Managed Bean to Store Information".

17.4.1 How to Set Parameters Using Command Components

You can use the setActionListener component to set values on other objects. This component must be a child to a command component.

To use the setActionListener component:

  1. Create a command component using either the Data Control Palette or the Component Palette.

  2. From the Component Palette, drag a setActionListener component and drop it as a child to the command component.

  3. In the Insert ActionListener dialog, set From to be the parameter value.

  4. Set To to be where you want to set the parameter value.

    Tip:

    Consider storing the parameter value on a managed bean or in scope instead of setting it directly on the resulting page's page definition file. By setting it directly on the next page, you lose the ability to easily change navigation in the future. For more information, see Section 17.2, "Using a Managed Bean to Store Information". Additionally, the data in a binding container is valid only during the request in which the container was prepared. Therefore, the data may change between the time you set it and the time the next page is rendered

17.4.2 What Happens When You Set Parameters

The setActionListener component lets the command component set a value before navigating. When you set the From attribute to the source of the value you need to pass, or the actual value, the component will be able to access that value. When you set the To attribute to a target, the command component is able to set the value on the target. Example 17-5 shows the code on the JSF page for a command component that takes the value false and sets that as the value of the searchFirstTime flag on the userState managed bean.

Example 17-5 JSF Page Code for a Command Button Using a setActionListener Component

<af:commandButton actionListener="#{bindings.Execute.execute}"
                 text="#{res['srsearch.searchLabel']}">
  <af:setActionListener from="#{false}"
                           to="#{userState.searchFirstTime}"/>
</af:commandButton>

17.4.3 What Happens at Runtime

When a user clicks the command component, before navigation occurs, the setActionListener component sets the parameter value. In Example 17-5, the setActionListener takes the value false and sets it as the value for the searchFirstTime attribute on the userState managed bean. Now, any component that needs to know this value in determining whether or not to render, can access it using the EL expression #{userState.searchFirstTime}. For the complete example Section 18.5, "Conditionally Displaying the Results Table on a Search Page".

17.5 Overriding Declarative Methods

When you drop an operation or method as a command button, JDeveloper binds the button to the execute method for the operation or method. However, there may be occasions when you need to add logic before or after the logic executes. For example, after the Delete operation successfully executes, you may want to execute the Commit operation, so that the user does not have to click another button.

JDeveloper allows you to add logic to a declarative operation by creating a new method and property on a managed bean that provide access to the binding container. By default, this generated code executes the operation or method. You can then add logic before or after this code. JDeveloper automatically binds the command component to this new method instead of the execute property on the original operation or method. Now when the user clicks the button, the new method is executed.

Following are some of the instances in the SRDemo application where backing beans contain methods that inject the binding container and then add logic before or after the declarative method is executed:

17.5.1 How to Override a Declarative Method

In order to override a declarative method, you must have a managed bean to hold the new method to which the command component will be bound. If your page has a backing bean associated with it, JDeveloper adds the code needed to access the binding object to this backing bean. If your page does not have a backing bean, JDeveloper asks you to create one.

Note:

You cannot use the following procedure if the command component currently has an EL expression as its value for the Action attribute, as JDeveloper will not overwrite an EL expression. You must remove this value before continuing.

To override a declarative method:

  1. Drag the operation or method to be overridden onto the JSF page and drop it as a UI command component.

    Doing so creates the component and binds it to the associated binding object in the ADF Model layer using the ActionListener attribute on the component.

    For more information about creating command components using methods on the Data Control Palette, see Section 17.3, "Creating Command Components to Execute Methods".

    For more information about creating command components from operations, see Section 13.4.2, "What Happens When Command Buttons Are Created Using the Data Control Palette"

  2. On the JSF page, double-click on the component.

    In the Bind Action Property dialog, identify the backing bean and the method to which you want to bind the component using one of the following techniques:

    • If auto-binding has been enabled on the page, the backing bean is already selected for you, as shown in Figure 17-4.

      Figure 17-4 Bind Action Property Dialog for a Page with Auto-Binding Enabled

      Bind Actin Property Dialog for a Page Using Auto-binding
      • To create a new method, enter a name for the method in the Method field, which initially displays a default name.

        OR

      • To use an existing method, select a method from the dropdown list in the Method field.

      • Select Generate ADF Binding Code.

    • If the page is not using auto-binding, you can select from an existing backing bean or create a new one, as shown in Figure 17-5. For more information about auto-binding, see Section 11.5.4, "How to Use the Automatic Component Binding Feature".

      Figure 17-5 Bind Action Property Dialog for a Page with Auto-Binding Disabled

      Bind Action Property dialog for page not using auto-binding
      • Click New to create a new backing bean. The Create Managed Bean dialog is displayed. Use this dialog to name the bean and the class, and set the bean's scope.

        OR

      • Select an existing backing bean and method from the dropdown lists.

    Note:

    If you are creating a new managed bean, then you must set the scope of the bean to request. Setting the scope to request is required because the data in the binding container object that will be referenced by the generated code is on the request scope, and therefore cannot "live" beyond a request.

    Additionally, JDeveloper understands that the button is bound to the execute property of a binding whenever there is a value for the ActionListener attribute on the command component. Therefore, if you have removed that binding, you will not be given the choice to generate the ADF binding code. You need to either inject the code manually, or to set a dummy value for the ActionListener before double-clicking on the command component.

  3. After identifying the backing bean and method, click OK in the Bind Action Property dialog

    JDeveloper opens the managed bean in the source editor. Example 17-6 shows the code inserted into the bean. In this example, a command button is bound to the Delete operation.

    Example 17-6 Generated Code in a Backing Bean to Access the Binding Object

    public BindingContainer getBindings() {
    
          return this.bindings;
      }
        
      public void setBindings(BindingContainer bindings) {
          this.bindings = bindings;
      } 
    
      public String commandButton_action1() {
          BindingContainer bindings = getBindings();
          OperationBinding operationBinding =
              bindings.getOperationBinding("Delete");
          Object result = operationBinding.execute();
          if (!operationBinding.getErrors().isEmpty()) {
              return null;
          }
          return null;
      }
    
  4. You can now add logic either before or after the binding object is accessed.

    Tip:

    To get the result of an EL expression, you need to use the ValueBinding class, as shown in Example 17-7

    Example 17-7 Accessing the Result of an EL Expression in a Managed Bean

    FacesContext fc = FacesContext.getCurrentInstance();
      ValueBinding expr = 
        fc.getApplication().
          createValueBinding("#{bindings.SomeAttrBinding.inputValue}");
    DCIteratorBinding ib = (DCIteratorBinding)
      expr.getValue(fc);
    

    In addition to any processing logic, you may also want to write conditional logic to return one of multiple outcomes depending on certain criteria. For example, you might want to return null if there is an error in the processing, or another outcome value if the processing was successful. A return value of null causes the navigation handler to forgo evaluating navigation cases and to immediately redisplay the current page.

    Tip:

    To trigger a specific navigation case, the outcome value returned by the method must exactly match the outcome value in the navigation rule in a case-sensitive way.

    The command button is now bound to this new method using the Action attribute instead of the ActionListener attribute. If a value had previously existed for the Action attribute (such as an outcome string), that value is added as the return for the new method. If there was no value, the return is kept as null.

17.5.2 What Happens When You Override a Declarative Method

When you ovrerride a declarative method, JDeveloper adds a managed property to your backing bean with the managed property value of #{bindings} (the reference to the binding container), and it adds a strongly-typed bean property to your class of the BindingContainer type which the JSF runtime will then set with the value of the managed property expression #{bindings}. JDeveloper also adds logic to the UI command action method. This logic includes the strongly-typed getBindings() method used to access the current binding container.

Example 17-8 shows the code that JDeveloper adds to the chosen managed bean. Notice that the return String "Complete" was automatically added to the method, as that was the value of the action attribute.

Example 17-8 Generated Code in a Backing Bean to Access the Binding Object

private BindingContainer bindings;
...
public String createSRButton_action() {
    BindingContainer bindings = getBindings();
    OperationBinding operationBinding = 
            bindings.getOperationBinding("createServiceRequest");
    Object result = operationBinding.execute();
    if (!operationBinding.getErrors().isEmpty()) {
        return null;
    }
 
    return "Complete";
}

This code does the following:

  • Accesses the binding container

  • Finds the binding for the associated method, and executes it

  • Adds a return for the method that can be used for navigation. By default the return is null, or if an outcome string had previously existed for the button's Action attribute, that attribute is used as the return value. You can change this code as needed. For more information about using return outcomes, see Section 16.4, "Using Dynamic Navigation".

JDeveloper automatically rebinds the UI command component to the new method using the Action attribute, instead of the ActionListener attribute. For example, Example 17-9 shows the code on a JSF page for a command button created by dropping the createServiceRequest method. Notice that the actionListener attribute is bound to the createServiceRequest method, and the action attribute has a String outcome of Complete. If the user were to click the button, the method would simply execute, and navigate to the page defined as the toViewId for this navigation case.

Example 17-9 JSF Page Code for a Command Button Bound to a Declarative Method

<af:commandButton actionListener="#{bindings.createServiceRequest.execute}"
                  text="createServiceRequest"
                  disabled="#{!bindings.createServiceRequest.enabled}"
                  id="createSRButton" 
                  action="Complete"/>

Example 17-10 shows the code after overriding the method on the page's backing bean. Note that the action attribute is now bound to the backing bean's method.

Example 17-10 JSF Page Code for a Command Button Bound to an Overridden Method

<af:commandButton text="createServiceRequest"
                  disabled="#{!bindings.createServiceRequest.enabled}"
                  id="createSRButton"
                  action="#{backing_SRCreateConfirm.createSRButton_action}"/>

Tip:

If when you click the button that uses the overridden method, you receive this error:

SEVERE: Managed bean main_bean could not be created The scope of the referenced object: '#{bindings}' is shorter than the referring object

it is because the managed bean that contains the overriding method has a scope that is greater than request, (that is, either session or application). Because the data in the binding container referenced in the method has a scope of request, the scope of this managed bean must be set to request scope or a lesser scope.