Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3) B25386-01 |
|
![]() Previous |
![]() Next |
You can create a form that allows a user to enter information for a new record and then commit that record into the data source. When the session bean for your data control is created, by default, constructor methods are created for objects on the data control. For example, the SRPublicFacade session bean in the SRDemo application has constructor methods for products, expertise areas, service histories, users, and service requests. The constructors provide an easy way to declaratively create an object that can be passed to a method. For example, by default, session beans have a persistEntity(Object)
CRUD method that can be used to persist new records to the database (for more information about the default session bean methods, see Section 3.2.1.2). When you use the constructor method to create an input form, that method is called to create the object and initialize the object's variables to the entered values. You can then easily pass the constructor's results to the persistEntity
method, which will create the new record in the data source.
There may be instances, however, when you need more control over how the new object is created. For example, you may want certain attributes to be populated programmatically. In this case, you might create a custom method to handle the creation of objects. To use a custom method to create an input form, instead of dropping the collection returned from a method, you drop the method itself as a parameter form. JDeveloper automatically adds a command button bound to the method, so that the custom create method will execute when the user clicks the button.
For example, the SRDemo application's SRPublicFacade
data control contains the createServiceRequest(String, Integer, Integer)
method. String
represents the value for the problem description, the first Integer
represents the product ID, and the second Integer
represents the ID of the user who created the request. This method creates a new instance of a ServiceRequest
object using the values of the parameters to populate the attributes on the object; however, the product ID and the ID of the user are set by the method instead of by the user.
Constructors for a data control are located in its Constructor folder. These access the default methods on the data control used to create an object (for more information, see Section 3.2.1.2, "Generating Session Facade Methods"). Figure 10-8 shows the constructors for the SRPublicFacade
data control.
To create an input form using a constructor:
From the Data Control Palette, drag the appropriate constructor onto the JSF page. Constructors can only be dropped as a form, so no context menu displays.
In the Edit Form Fields dialog, set the labels, bindings, and UI components. Do not select Include Submit Button.
From the Data Control Palette, drag the persistEntity(Object)
method. This method persists the object created by the constructor to the database.
In the context menu, choose Methods > ADF Command Button.
In the Action Binding Editor, enter the value for the entity
parameter by clicking the ellipses (...) button in the Value field to launch the EL Expression Builder. Since you want the entity parameter to be the result of the constructor, select the result under the action binding for the constructor, as shown in Figure 10-9.
When you use a constructor to create an input form, JDeveloper:
Creates an action binding for the constructor method, a method iterator binding for the result of constructor method, and attribute bindings for each of the attributes of the object. It also creates an invoke action in the executables that causes the constructor method to execute during the Render Model phase.
Inserts code in the JSF page for the form using ADF Faces inputText
components.
For example, to create a simple input form for products in the SRDemo application, you might drop the product constructor method from the Data Control Palette as a parameter form, and then drop the persistEntity
method as a button below the form, as shown in Figure 10-10.
Note: This page is an example only and does not exist in the SRDemo application. |
Example 10-12 shows the page definition file for this input form. When the invoke action binding executes, the constructor method is called using the action binding. The result of that constructor method is then bound to the iterator. When you drop the persistEntity(Object)
method as a command button, that method can access the result of the constructer through the iterator.
Example 10-12 Page Definition Code for a Constructor
<executables> <invokeAction Binds="Product" id="invokeProduct" Refresh="renderModel" RefreshCondition="${!adfFacesContext.postback and empty bindings.exceptionsList}"/> <methodIterator DataControl="SRPublicFacade" BeanClass="oracle.srdemo.model.entities.Product" Binds="Product.result" id="ProductIter" Refresh="renderModel" RefreshCondition="${!adfFacesContext.postback and empty bindings.exceptionsList}"/> </executables> <bindings> <methodAction DataControl="SRPublicFacade" id="Product" MethodName="Product" RequiresUpdateModel="true" Action="999" ReturnName="SRPublicFacade.methodResults.SRPublicFacade_ Product_result" ClassName="oracle.srdemo.model.entities.Product"/> <attributeValues id="description" IterBinding="ProductIter"> <AttrNames> <Item Value="description"/> </AttrNames> </attributeValues> <attributeValues id="image" IterBinding="ProductIter"> <AttrNames> <Item Value="image"/> </AttrNames> </attributeValues> <attributeValues id="name" IterBinding="ProductIter"> <AttrNames> <Item Value="name"/> </AttrNames> </attributeValues> <attributeValues id="prodId" IterBinding="ProductIter"> <AttrNames> <Item Value="prodId"/> </AttrNames> </attributeValues> <methodAction id="persistEntity" InstanceName="SRPublicFacade.dataProvider" DataControl="SRPublicFacade" MethodName="persistEntity" RequiresUpdateModel="true" Action="999" ReturnName="SRPublicFacade.methodResults.SRPublicFacade_ dataProvider_persistEntity_result"> <NamedData NDName="entity" NDValue="${bindings.Product.result}" NDType="java.lang.Object"/> </methodAction> </bindings>
Anytime the constructor method is invoked, an object is created. However, since data is cached, (which allows the method to do a postback to the server), the constructor method will create the same object again when the user revisits the page, perhaps to create another object. Additionally, if errors occur, when the page is rerendered with the error message, the object would again be created.
To prevent duplicates, the invoke action's refreshCondition
property is set so that the constructor will only be invoked whenever there has been no postback to the server and as long as there are no error messages. See Example 10-12 for the EL expression.
The iterator has the same refresh condition. This setting prevents the iterator from displaying the cached data used in the postback, and instead allows the form to display without any data when the user revisits the page.
When you use a custom method to create an input form, you drag the method that can take the data populated by the user and drop it as a parameter form. In this case, since you need to create an object, you cannot drop a return. You drop the method itself.
To create an input form using a custom method:
From the Data Control Palette, drag the appropriate method onto the JSF page.
From the context menu select Parameters > ADF Parameter Form.
The Edit Form Fields dialog opens, which allows you to customize the labels, bindings, and UI components before creating the form. JDeveloper automatically adds a command button bound to the method.
When you drop a method as a parameter form, JDeveloper:
Defines variables to hold the data values, a method binding for the method, and the attribute bindings for the associated attributes in the page definition file.
Inserts code in the JSF page for the form using ADF Faces inputText
components and an ADF Faces command button component. This code is the same as code for any other input form or command button.
Just as when you drop a collection that is a return of a method that takes parameters, when you drop the method itself onto a JSF page, JDeveloper creates NamedData
elements for each parameter. However, since the user will provide the parameter values (instead of another page providing the values, as described in Section 10.6, "Creating a Form or Table Using a Method that Takes Parameters"), each NamedData
element is bound to the attribute binding for the corresponding attribute. This binding allows the method to access the correct attribute's value for the parameter on execution.
For example, the createServiceRequest
method action binding contains a NamedData
element for each of the parameters it takes. The NamedData
elements are then bound to a corresponding attribute binding using an EL expression. Example 10-13 shows the method action binding and some of the attribute bindings created when you drop the createServiceRequest
method.
Example 10-13 Method Action Binding in the Page Definition File
<bindings> <methodAction id="createServiceRequest" MethodName="createServiceRequest" RequiresUpdateModel="true" Action="999" DataControl="SRPublicFacade" InstanceName="SRPublicFacade.dataProvider" ReturnName="SRPublicFacade.methodResults.SRPublicFacade_ dataProvider_createServiceRequest_result"> <NamedData NDName="problemDescription" NDType="java.lang.String" NDValue="${bindings.createServiceRequest_problemDescription}"/> <NamedData NDName="productId" NDType="java.lang.Integer" NDValue="${bindings.createServiceRequest_productId}"/> <NamedData NDName="createdBy" NDType="java.lang.Integer" NDValue="${bindings.createServiceRequest_createdBy}"/> </methodAction> <attributeValues id="problemDescription" IterBinding="variables"> <AttrNames> <Item Value="createServiceRequest_problemDescription"/> </AttrNames> </attributeValues> <attributeValues id="productId" IterBinding="variables"> <AttrNames> <Item Value="createServiceRequest_productId"/> </AttrNames> ... </attributeValues> </bindings>
Note that like the attributes for a collection, attributes for a method also reference an iterator. However, instead of referencing a method iterator that accesses and iterates over the collection that the associated method returns, attributes for a creation-type method access and iterate over variables. Because this type of method has not returned an object, there is nothing to hold the values entered on the page. Variables act as the data holders.
JDeveloper creates a variable for each parameter the method takes. The variables are declared as children to the variable iterator, and are local, meaning they "live" only as long as the associated binding context. Example 10-14 shows the variable iterator and variables created when you use the createServiceRequest(String, Integer, Integer)
method.
Example 10-14 Variable Iterator and Variables in the Page Definition File
<executables> <variableIterator id="variables"> <variable Type="java.lang.String" Name="createServiceRequest_problemDescription" IsQueriable="false"/> <variable Type="java.lang.Integer" Name="createServiceRequest_productId" IsQueriable="false"/> <variable Type="java.lang.Integer" Name="createServiceRequest_createdBy" IsQueriable="false"/> </variableIterator> </executables>
When the user enters data and submits the form, the variables are populated and the attribute binding can then provide the value for the method's parameters using the EL expression for the value of the NamedData
element.
The service request creation process in the SRDemo application uses a process train, which causes the actual creation of the request to be spread out over three steps (for more information, see Section 11.5, "Creating a Multipage Process"). For the purposes of this explanation, assume the process is contained on one page. When the user enters a description in the corresponding inputText
component and clicks the Create Product button, the following happens:
The problemDescriptionVar
variable is populated with the value the user entered.
Because the problemDescription
attribute binding refers to the variable iterator, and to the problemDescriptionVar
variable specifically as its Item
value, the attribute binding can get the description:
<attributeValues id="problemDescription" IterBinding="variables"> <AttrNames> <Item Value="createServiceRequest_problemDescription"/> </AttrNames> </attributeValues>
Because the Name
NamedData
element has an EL expression that evaluates to the item value of the problemDescription
attribute binding, it can also access the value:
<NamedData NDName="problemDescription" NDType="java.lang.String" NDValue="${bindings.createServiceRequest_problemDescription}"/>
The createServiceRequest
method is executed with each parameter taking its value from the corresponding NamedData
element.