33 Using Command Components to Invoke Functionality in the View Layer

This chapter describes how to invoke custom methods on ADF Business Components using ADF Faces command components and ADF Model data bindings in the Fusion web application. Specifically, it describes how you can use ADF Faces components to invoke ADF Business Components client interface methods, including how to pass parameters to a method and how to override the declarative method created when you drag and drop a method from the Data Controls panel.

This chapter includes the following sections:

33.1 About Command Components

Command components are represented by the UICommand component, which performs an action when it is activated. ADF Faces command components deliver action events when the components are activated.

Once you create a basic page and add navigation capabilities, you may want to add more complex features, such as passing parameters between pages or providing the ability to override declarative actions. Oracle ADF provides many features that allow you to add this complex functionality using very little actual code.

Some of the implementation methods in this chapter are intended for page-level designs. You may be able to perform many of the same functions by using task flows. See Getting Started with ADF Task Flows.

33.1.1 Command Component Use Cases and Examples

You can use command components to perform an action, such as passing parameters, overriding declarative actions, or performing some logic. You can bind a command component to a custom method in the Data Controls panel. For example, if you have a custom method called deleteOrderItem(), you can create a button bound to this method so that when the user presses this button, the order item will be deleted.

You can also use the setPropertyListener tag within a command component to assign values when an event fires. For example, assume you have a button that initiates a search and displays the results on another page depending on a parameter value stored in a managed bean. You can use the setPropertyListener property to pass this parameter value to the method that checks this value.

You can add code to a declarative method that is bound to a command component. For example, after you have created a declarative Commit button, you can add code to a managed bean and then override the Commit operation for additional processing

33.1.2 Additional Functionality for Command Components

You may find it helpful to understand other Oracle ADF features before you work with command components. Following are links to other functionality that may be of interest.

33.2 Creating Command Components to Execute Methods

The Data Controls panel contains custom methods that invoke application logic from anywhere within an ADF application's control flow. You can drag a method and drop it as a command button to execute the method.

When your application contains custom methods, these methods appear in the Data Controls panel. 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 creating custom methods, see Customizing an Application Module with Service Methods, and Publishing Custom Service Methods to UI Clients.

Note:

If you are using task flows, you can call methods directly from the task flow definition. For more information, see Using Method Call Activities.

For example, the ItemsForOrder view object in the Summit sample application for Oracle ADF contains the deleteOrderItem() method. This method updates the items in the shopping cart. To allow the user to execute this method, you drag the deleteOrderItem() method from the Data Controls panel, as shown in Figure 33-1.

Figure 33-1 Methods in the Data Controls Panel

Description of Figure 33-1 follows
Description of "Figure 33-1 Methods in the Data Controls Panel"

In order to perform the required business logic, many methods require a value for their parameter or parameters. This means that when you create a button bound to the method, you need to create an EL expression to specify where the value for the parameter(s) is to be retrieved from. For example, if you use the populateInventoryForProduct(String productId) method, you need to configure the method action binding to retrieve a product ID so that the method can display the inventory for the product with that ID.

33.2.1 How to Create a Command Component Bound to a Custom Method

You create a command component bound to custom method by dragging the custom method from the Data Controls panel to a form.

Before you begin:

It may be helpful to have an understanding of custom methods. For more information, see Creating Command Components to Execute Methods.

You may also find it helpful to understand functionality that can be added using other command components. For more information, see Additional Functionality for Command Components.

You will need to complete these tasks:

To create a command component bound to a custom method:

  1. From the Data Controls panel, 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 Create > Methods > ADF Button.

    If the method takes parameters, the Edit Action Binding dialog opens. In the Edit Action Binding dialog, enter values for each parameter or click the Show EL Expression Builder menu selection in the Value column of Parameters to launch the EL Expression Builder.

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

  • Binds the button to the method using actionListener.

  • Uses the return value from the method call.

33.2.2.1 Action Bindings

JDeveloper adds an action binding for the method. Action bindings use the RequiresUpdateModel property, which determines whether or not the model needs to be updated before the action is executed. For command operations, this property is set to true by default, which means that any changes made at the view layer must be moved to the model before the operation is executed.

33.2.2.2 Method Parameters

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, in the Summit sample application for ADF task flows, the populateInventoryForProduct(String) method action binding contains a NamedData element for the String parameter. This element is bound to the value specified when you created the action binding. The following example shows the method action binding created when you drop the populateInventoryForProduct(String) method, and bind the String parameter (named productId) to the appropriate variable.

<methodAction id="populateInventoryForProduct" RequiresUpdateModel="true"
              Action="invokeMethod"
              MethodName="populateInventoryForProduct" IsViewObjectMethod="true"
              DataControl="BackOfficeAppModuleDataControl"
              InstanceName="data.BackOfficeAppModuleDataControl.InventoryVO1">
    <NamedData NDName="productId" NDType="java.lang.String"/>
</methodAction>

33.2.2.3 ADF Faces Component Code

JDeveloper adds code for the ADF Faces component to the JSF page. This code is similar to the code for any other command button, as described in EL Expressions Created to Bind to 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.

33.2.2.4 EL Expressions Used 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 using an EL expression. This EL expression causes the binding's method to be invoked on the application module. For more information about the command button's actionListener attribute, see What Happens at Runtime: How Action Events and Action Listeners Work.

Tip:

Instead of binding a button to the execute method on the action binding, you can bind the button to the 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 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. The following example shows the EL expression used to bind the command button to the populateInventoryForProduct(String) method.

<af:button actionListener="#{bindings.populateInventoryForProduct.execute}"
                       text="populateInventoryForProduct"     
                       disabled="#{!bindings.populateInventoryForProduct.enabled}"
                       id="b1"/>

Tip:

When you drop a command button component onto the page, JDeveloper automatically gives it an ID based on the number of the same type of component that was previously dropped. For example, b1 and b2 for the first two buttons dropped. If you change the ID to something more descriptive, you must manually update any references to it in any EL expressions in the page.

33.2.2.5 Using the Return Value from a Method Call

You can also use the return value from a method call. The following example shows a custom method that returns a string value.

/**
 * Custom method.
*/
    public String getHelloString() {
        return ("Hello World");
    }

The following example shows the code in the JSF page for the command button and an outputText component.

<af:button actionListener="#{bindings.getHelloString.execute}"
        text="getHelloString"
        disabled="#{!bindings.getHelloString.enabled}"
        id="helloButtonId"/>
<af:outputText value="#{bindings.return.inputValue}"
        id="helloOutputId"/>

When the user clicks the command button, it calls the custom method. The method returns the string "Hello World" to be shown as the value of the outputText component.

33.2.3 What Happens at Runtime: Command Button Method Bindings

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 populateInventoryForProduct(String productId) method, the method takes the value of the productId parameter and displays the inventory for that product.

33.3 Setting Parameter Values Using a Command Component

In order to determine complex ADF application functionality, you may need to set parameters to an action on a page. A managed bean can be used to successfully pass the parameter and a method on the bean checks the parameter.

There may be cases where an action on one page needs to set parameters that will be used to determine application functionality. For example, you can create a search button on one page that will navigate to a results table on another page. But the results table will display only if a parameter value is false.

You can use a managed bean to pass this parameter between the pages, and to contain the method that is used to check the value of this parameter. The managed bean is instantiated as the search page is rendered, and a 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.

For more information about creating custom methods, see Customizing an Application Module with Service Methods, and Publishing Custom Service Methods to UI Clients.

Note:

If you are using task flows, you can use the task flow parameter passing mechanism. See Using Parameters in Task Flows.

A setPropertyListener component with type property set to action, which is nested in the command button that executed this search, is then used to set this flag to false, thus causing the results table to display once the search is executed. For information about using managed beans, see Using a Managed Bean in a Fusion Web Application.

33.3.1 How to Set Parameters Using setPropertyListener Within a Command Component

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

Before you begin:

It may be helpful to have an understanding of how setPropertyListener and managed bean can be used to set a value. For more information, see Setting Parameter Values Using a Command Component.

You may also find it helpful to understand functionality that can be added using other command components. For more information, see Additional Functionality for Command Components.

You will need to complete this task:

To use the setPropertyListener component:

  1. In the Applications window, double-click the web page that contains the command component to which you want to add the listener.
  2. In the design editor for the page, right-click the command component and choose Insert Inside Button > ADF Faces.
  3. In the Insert ADF Faces Item dialog, select Set Property Listener and click OK.
  4. In the Insert Set Property Listener dialog, enter the parameter value in the From field.

    You can bring up an expression builder for this field by hovering to the right of the field, clicking the icon that appears, and choosing Expression Builder.

  5. Enter the parameter target in the To field.

    You can bring up an expression builder for this field by hovering to the right of the field, clicking the icon that appears, and choosing Expression Builder.

    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 Using a Managed Bean in a Fusion Web Application. Additionally, the data in a binding container is valid only during the request in which the container was prepared. The data may change between the time you set it and the time the next page is rendered.

  6. From the Type dropdown menu, select Action.
  7. Click OK.

33.3.2 What Happens When You Set Parameters Using a setPropertyListener

The setPropertyListener component lets the command component set a value before it navigates to the next page. When you set the from attribute either to the source of the value you need to pass or to 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. The following example shows the code on the JSF page for a command component that takes the value false and sets it as the value of the initialSearch flag on the searchResults managed bean.

<af:button actionListener="#{bindings.Execute.execute}"
                 text=Search>
      <af:setPropertyListener from="#{false}"
                          to="#{searchResults.initialSearch}"/>
                          type="action"/>
</af:button>

33.3.3 What Happens at Runtime: setPropertyListener for a Command Component

When a user clicks the command component, before navigation occurs, the setPropertyListener component sets the parameter value. As the example in What Happens When You Set Parameters Using a setPropertyListener illustrates, the setPropertyListener takes the value false and sets it as the value for the initialSearch attribute on the searchResults 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 #{searchResults.initialSearch}.

33.4 Overriding Declarative Methods

You can override the functionality of an existing declarative method to define a behavior that is specific to the method requirement. In order to add logic after or before the declarative method , you will need a new method and property on a managed bean that provides access to the associated action binding.

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 existing logic.

Note:

If you are using task flows, you can call custom methods from the task flow. For more information, see Getting Started with ADF Task Flows.

JDeveloper allows you to add logic to a declarative operation by creating a new method and property on a managed bean that provides 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 to the execute property on the original operation or method. Now when the user clicks the button, the new method is executed.

For example, in the Customers.jsff fragment of the Summit ADF task flow sample application, you can click the New icon to create a new order. However, the declarative CreateInsert operation requires additional processing. When the button is clicked, a new tab needs to be displayed showing the order details. To provide this processing, logic is added to the createNewOrder method in the CustomersBackingBean managed bean.

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.

33.4.1 How to Override a Declarative Method

You can add a command component and override its declarative methods using a managed bean.

Before you begin:

It may be helpful to have an understanding of how to override declarative methods. For more information, see Overriding Declarative Methods.

You may also find it helpful to understand functionality that can be added using other command components. For more information, see Additional Functionality for Command Components.

You will need to complete these tasks:

Note:

You cannot override the declarative method if the command component currently has an EL expression as its value for the Action attribute, because 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.

    The component is created and bound to the associated binding object in the ADF Model layer with the ActionListener attribute.

    For more information about creating command components using methods on the Data Controls panel, see Creating Command Components to Execute Methods.

    For more information about creating command components from operations, see What Happens When You Create Command Components Using Operations.

  2. On the JSF page, double-click the component.
  3. 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 (by selecting the Automatically Expose UI Components in a New Managed Bean option that is available on the Managed Bean tab of the Create JSF Page wizard), the backing bean is already selected for you.

      • 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 Use ADF Binding for Generation.

    • If the page is not using auto-binding, you can select from an existing backing bean or create a new one.

      • Click New to create a new backing bean. In the Create Managed Bean dialog, name the bean and the class, and set the bean's scope.

        or

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

      Figure 33-2 shows the Bind Action Property dialog with a method from a managed bean specified for the method binding.

      Figure 33-2 Bind Action Property Dialog

      Description of Figure 33-2 follows
      Description of "Figure 33-2 Bind Action Property Dialog"

    Note:

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

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

    The managed bean opens in the source editor. The following example shows the code inserted into the bean in the Summit ADF task flow sample application. In this example, a command button is bound to the CreateInsert operation.

    public void createNewOrder() {
            BindingContainer bindings = getBindings();
            OperationBinding operationBinding =
                  bindings.getOperationBinding("CreateInsert");
            Object result = operationBinding.execute();
            if (!operationBinding.getErrors().isEmpty()) {
                return null;
            }
    }
    
  5. You can now add logic either before or after the binding object is accessed, as shown by the code in bold in the following example.
    public void createNewOrder() {
    //This method is called when creating a new order 
    //to create the record and switch the tab
      getSdi3().setDisclosed(false);
      getSdi4().setDisclosed(true);
      BindingContainer bindings = getBindings();
      OperationBinding operationBinding =
           bindings.getOperationBinding("CreateInsert");
      operationBinding.execute();
      AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance();
      adfFacesContext.addPartialTarget(getSdi4()); 
    }
    

    In addition to any processing logic, you may also want to write conditional logic to return one of multiple outcomes. 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, including case.

    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.

33.4.2 What Happens When You Override a Declarative Method

When you override 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.

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

JDeveloper automatically rebinds the UI command component to the new method using the Action attribute, instead of the ActionListener attribute. The following example shows the code when a CreateInsert operation is declaratively added to a page.

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

The following example shows the code for the button tag after the method on the page's backing bean is overridden. Note that the action attribute is now bound to the backing bean's method.

<af:button text="New"
           action="#{backingBeanScope.CustomersBackingBean.createNewOrder}"/>

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 the same or a lesser scope.