Oracle® Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework 11g Release 2 (11.1.2.1.0) Part Number E16182-02 |
|
|
PDF · Mobi · ePub |
This chapter describes how to add more complex bindings to your pages. It describes how to use methods that take parameters for creating forms and command components.
This chapter includes the following sections:
Section 28.2, "Creating Command Components to Execute Methods"
Section 28.3, "Setting Parameter Values Using a Command Component"
Note:
Some of the implementation methods in this chapter are intended for page-level designs. If you are using task flows, you may be able to perform many of the same functions. For more information, see Chapter 18, "Getting Started with ADF Task Flows."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 functions described in this chapter may be performed using other methodology. For example, if you are using task flows instead of individual page flows, you should use the task flow parameter passing mechanism. Or, if you are using ADF Business Components, you should use the validation rules on entity objects in the data model project, rather than using ADF Model validation rules. For more information about validation rules for Business Components, see Chapter 7, "Defining Validation and Business Rules Declaratively."
You can use command components to perform an action, such as passing parameters, overriding declarative actions, or perform some logic. You can bind a command component to a custom method in the Data Control panel. For example, if you have a custom method called updateItemInCart(Integer, Integer, Boolean)
, you can create a button bound to this method so when the user presses this button, the shopping cart will be updated.
You can also use the setPropertyListener
tag within a command component to assign values when an event fires. For example, 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 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
You may find it helpful to understand other ADF features before you work with command components. Following are links to other functionality that may be of interest.
For information about creating custom methods that can be added to the page as a command component, see Section 9.7, "Customizing an Application Module with Service Methods," and Section 9.9, "Publishing Custom Service Methods to UI Clients."
For information about creating command components from operations, see Section 26.4.2, "What Happens When You Create Command Buttons."
If you want to use EL expressions in your methods, see Section 26.4.2.3, "EL Expressions Used to Bind to Navigation Operations."
For more information about the command button's actionListener
attribute, see Section 26.4.3, "What Happens at Runtime: How Action Events and Action Listeners Work."
For more information about ADF bindings, see Section 13, "Using ADF Model in a Fusion Web Application."
If you are using task flows, you can use the task flow parameter passing mechanism. For more information, see Chapter 20, "Using Parameters in Task Flows."
If you considering using task flow call methods, see Section 19.5, "Using Method Call Activities."
If you are using managed beans, see Section 24.4, "Using a Managed Bean in a Fusion Web Application."
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 Section 9.7, "Customizing an Application Module with Service Methods," and Section 9.9, "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 Section 19.5, "Using Method Call Activities."For example, the application module in the StoreFront module of the Fusion Order Demo application contains the updateItemInCart(Integer, Integer, Boolean)
method. This method updates the items in the shopping cart. To allow the user to execute this method, you drag the updateItemInCart(Integer, Integer Boolean)
method from the Data Controls panel, as shown in Figure 28-1.
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 specify where the value for the parameter(s) is to be retrieved from. For example, if you use the updateItemInCart(Integer, Integer, Boolean)
method, you need to specify the items to be updated.
It may be helpful to have an understanding of custom methods. For more information, see Section 28.2, "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 Section 28.1.2, "Additional Functionality for Command Components."
To create a command component bound to a custom method:
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.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.
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.
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.
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 updateItemInCart(Integer, Integer, Boolean)
method action binding contains NamedData
elements for the parameter. This element is bound to the value specified when you created the action binding. Example 28-1 shows the method action binding created when you drop the updateItemInCart(Integer, Integer, Boolean)
method, and bind the Integer
parameter (named productId
) and the other Integer
parameter (named quantity
) and the Boolean
parameter (named isSet
) to the appropriate variables.
Example 28-1 Method Action Binding for a Parameter Method
<methodAction id="updateItemInCart" InstanceName="StoreServiceAMDataControl.dataProvider" DataControl="StoreServiceAMDataControl" RequiresUpdateModel="true" Action="invokeMethod" MethodName="updateItemInCart" IsViewObjectMethod="false"> <NamedData NDName="productId" NDType="java.lang.Integer"/> <NamedData NDName="quantity" NDType="java.lang.Integer"/> <NamedData NDName="isSet" NDType="java.lang.Boolean"/> </methodAction>
JDeveloper adds code for the ADF Faces component to the JSF page. This code is the same as code for any other command button, as described in Section 26.4.2.3, "EL Expressions Used 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.
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 Section 26.4.3, "What Happens at Runtime: How Action Events and Action Listeners Work."
Tip:
Instead of binding a button to theexecute
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 Section 28.4, "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 28-2 shows the EL expression used to bind the command button to the updateItemInCart(Integer, Integer, Boolean)
method.
Example 28-2 JSF Code to Bind a Command Button to a Method
<af:commandButton actionListener="#{bindings.updateItemInCart.execute}" text="updateItemInCart" disabled="#{!bindings.updateItemInCart.enabled}"/>
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,commandButton1
, commandButton2
. If you change the ID to something more descriptive, you must manually update any references to it in any EL expressions in the page.You can also use the return value from a method call. Example 28-3 shows a custom method that returns a string value.
Example 28-3 Custom Method That Returns a Value
/** * Custom method. */ public String getHelloString() { return ("Hello World"); }
Example 28-4 shows the code in the JSF page for the command button and an outputText
component.
Example 28-4 Command Button to Call the Custom Method
<af:commandButton 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.
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 updateItemInCartItem(Integer, Integer, Boolean)
method, the method takes the values of the product Id
and quantity and updates the shopping cart.
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 command 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 Section 9.7, "Customizing an Application Module with Service Methods," and Section 9.9, "Publishing Custom Service Methods to UI Clients."
Note:
If you are using task flows, you can use the task flow parameter passing mechanism. For more information, see Chapter 20, "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 Section 24.4, "Using a Managed Bean in a Fusion Web Application."
You can use the setPropertyListener
component to set values on other objects. This component must be a child of a command component.
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 Section 28.3, "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 Section 28.1.2, "Additional Functionality for Command Components."
You will need to complete this task:
To use the setPropertyListener component:
In the Component Palette, from the Operations panel, drag a setPropertyListener component and drop it as a child to the command component.
Or right-click the component and select Insert inside Button > ADF Faces > setPropertyListener.
In the Insert Set Property Listener dialog, enter the parameter value in the From field.
Enter the parameter target in the To field.
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 24.4, "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.From the Type dropdown menu, select Action.
Click OK.
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. Example 28-5 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.
When a user clicks the command component, before navigation occurs, the setPropertyListener
component sets the parameter value. In Example 28-4, 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}
.
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 Section 18, "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 Fusion Order Demo application Orders page, the Commit
operation requires additional processing. The Commit button is renamed to Submit Orders and logic is added to the submitOrders
method in the orderPageBean
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.
You can add a command component and override its declarative methods using a managed bean.
It may be helpful to have an understanding of how to override declarative methods. For more information, see Section 28.4, "Overriding Declarative Methods."
You may also find it helpful to understand functionality that can be added using other command components. For more information, see Section 28.1.2, "Additional Functionality for Command Components."
You will need to complete this task:
Note:
You cannot override the declarative method if the command component currently has an EL expression as its value for theAction
attribute, because JDeveloper will not overwrite an EL expression. You must remove this value before continuing.To override a declarative method:
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 Section 28.2, "Creating Command Components to Execute Methods."
For more information about creating command components from operations, see Section 26.4.2, "What Happens When You Create Command Buttons."
On the JSF page, double-click 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 28-2.
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, as shown in Figure 28-3.
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.
Note:
Whenever there is a value for theActionListener
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.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 28-6 shows the code inserted into the bean. In this example, a command button is bound to the Commit
operation.
Example 28-6 Generated Code in a Backing Bean to Access the Binding Object
public String submitOrder() { BindingContainer bindings = getBindings(); OperationBinding operationBinding = bindings.getOperationBinding("Commit"); Object result = operationBinding.execute(); if (!operationBinding.getErrors().isEmpty()) { return null; } }
You can now add logic either before or after the binding object is accessed, as shown in Example 28-7.
Example 28-7 Code Added to the Overridden Method
public String submitOrder() { DCBindingContainer bindings = (DCBindingContainer)JSFUtils.resolveExpression("#{bindings}"); OperationBinding operationBinding = bindings.getOperationBinding("Commit"); JUCtrlAttrsBinding statusCode = (JUCtrlAttrsBinding)bindings.findNamedObject("OrderStatusCode"); statusCode.setAttribute("OrderStatusCode", "PENDING"); JUCtrlAttrsBinding orderDate = (JUCtrlAttrsBinding)bindings.findNamedObject("OrderDate"); orderDate.setAttribute("OrderDate", new Date()); JUCtrlAttrsBinding orderId = (JUCtrlAttrsBinding)bindings.findNamedObject("OrderId"); JSFUtils.storeOnSession("orderId", orderId.getAttribute("OrderId")); JUCtrlAttrsBinding invoiceTotal = (JUCtrlAttrsBinding)bindings.findNamedObject("InvoiceTotal"); JUCtrlAttrsBinding orderTotal = (JUCtrlAttrsBinding)bindings.findNamedObject("OrderTotal"); orderTotal.setAttribute("OrderTotal", invoiceTotal.getAttribute("InvoiceTotal")); Object result = operationBinding.execute(); ShoppingCartBean shoppingCartBean = (ShoppingCartBean)JSFUtils.resolveExpression("#{shoppingCartBean}"); shoppingCartBean.removeAllItems(); return "orderSummary"; }
The code in Example 28-7 uses the FOD utility method JSFUtils.resolveExpression
to resolve EL expressions. The code for such a method would be similar to the code in Example 28-8.
Example 28-8 Utility Method to Solve EL Expressions
public static Object resolveExpression(String expression) { FacesContext facesContext = getFacesContext(); Application app = facesContext.getApplication(); ExpressionFactory elFactory = app.getExpressionFactory(); ELContext elContext = facesContext.getELContext(); ValueExpression valueExp = elFactory.createValueExpression(elContext, expression, Object.class); return valueExp.getValue(elContext); }
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
.
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. Example 28-9 shows the code when a Commit
operation is declaratively added to a page.
Example 28-9 JSF Page Code for a Command Button Bound to a Declarative Method
<af:commandButton actionListener="#{bindings.Commit.execute}" text="Commit" disabled="#{!bindings.Commit.enabled}"/>
Example 28-10 shows the code 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.
Example 28-10 JSF Page Code for a Command Button Bound to an Overridden Method
<af:commandButton text="#{res['order.cart.submit']}" action="#{orderPageBean.submitOrder}"/>
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.