Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers 10g (10.1.3.1.0) Part Number B25947-01 |
|
|
View PDF |
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. While you can choose to use the default ADF Form and then drop the Create operation as a command button, when this type of form is first rendered, it displays the data for the first instance in the collection. The ADF Creation form allows users to create new instances in the collection without first displaying existing instances.
There may be times, however, when you need more control over how a new object is created. For example, you may want certain attributes to be populated programmatically. In this case, you might create a custom method on your application module to handle the creation of objects. To use a custom method to create an input form, instead of using an ADF Creation form, you use a standard form and then drop a custom method as a command button. The custom method will execute when the user clicks the button.
Note: When you create a row programmatically, you should call theNewRow.setNewRowState(RowSet.STATUS_INITIALIZED method to get the same behavior as the built-in Create action. For more information, see Section 10.4.4, "What You May Need to Know About Create and CreateInsert". |
You create an input form similar to the way you create any other form. However, by selecting an ADF Creation Form when dropping a collection, JDeveloper provides additional functionality automatically.
To create an input form:
From the Data Control Palette, drag the collection for which you wish to create the form, and select ADF Creation Form from the context menu.
In the Edit Form Fields dialog, do not include the Submit button.
From the Data Control Palette, drag the Commit and Rollback operations associated with the root data control, and drop them as command buttons or links.
In the Structure window, select the command button for the commit operation.
In the Property Inspector, set the command button's Disabled property to False
.
By default, JDeveloper binds the Disabled
attribute of the button to the Enabled
property of the binding, causing the button to be disabled when the Enabled
property is set to False
. For this binding, the Enabled
property is false
until an update has been posted. For the purposes of an input form, the button should always be enabled, since there will be no changes posted before the user needs to create the new object.
When you use an ADF Creation Form to create an input form, JDeveloper:
Creates an iterator binding for the collection, an action binding for the Create operation, and attribute bindings for each of the attributes of the object in the collection. It also creates an invoke action in the executables section of the page definition that causes the Create
operation to execute during the Render Model phase. If you created command buttons or links using the Commit
and Rollback
operations, JDeveloper also creates an action bindings for those operations.
Inserts code in the JSF page for the form using ADF Faces inputText
components, and in the case of the operations, commandButton
components.
For example, to create a simple input form for products in the SRDemo application, you might drop the ProductsList
collection from the Data Control Palette as an ADF Creation Form, and then drop the Commit operation as a button below the form, as shown in Figure 13-10.
Note: This page is an example only and does not exist in the SRDemo application. |
Example 13-13 shows the page definition file for this input form. When the invoke action executes during the prepare render lifecycle phase, the Create
operation is invoked, and a new instance for the collection is created. For more information about the lifecycle, see Chapter 13, "What Happens at Runtime: The JSF and ADF Lifecycles"
Example 13-13 Page Definition Code for a Creation Form
<executables> <iterator id="ProductListIterator" RangeSize="10" Binds="ProductList" DataControl="SRService"/> <invokeAction Binds="Create" id="invokeCreate" Refresh="renderModel" RefreshCondition="${!adfFacesContext.postback and empty bindings.exceptionsList}"/> </executables> <bindings> <action id="Create" RequiresUpdateModel="true" Action="41" IterBinding="ProductListIterator" InstanceName="SRServiceDataControl.ProductList" DataControl="SRServiceDataControl"/> <attributeValues id="ProdId" IterBinding="ProductListIterator"> <AttrNames> <Item Value="ProdId"/> </AttrNames> </attributeValues> <attributeValues id="Name" IterBinding="ProductListIterator"> <AttrNames> <Item Value="Name"/> </AttrNames> </attributeValues> <attributeValues id="Description" IterBinding="ProductListIterator"> <AttrNames> <Item Value="Description"/> </AttrNames> </attributeValues> <action id="Commit" InstanceName="SRServiceDataControl" DataControl="SRServiceDataControl" RequiresUpdateModel="true" Action="100"/> </bindings>
Anytime the Create
operation is invoked (for example, when the page is first rendered), an data object is created. However, since data is cached (which allows the Create
operation to do a postback to the server), and since the Create
operation is invoked whenever the page enters the renderModel
phase, the Create
operation 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 Create operation will only be invoked whenever there has been no postback to the server and as long as there are no error messages (see Example 13-13 for the EL expression). When the user clicks the Commit button (which is bound to the Commit action through an action binding), the new object with the data is submitted to the data source. If you do want the user to be able to stay on the same page to create multiple objects, see Chapter 13, "What You May Need to Know About Create Forms and the RefreshCondition".
Because the invokeCreate
action is executed before the page is displayed, if you are populating the primary key (in this case the Product ID) using sequences, that number will appear in the input text field. For example, instead of being blank, the Product ID in Figure 13-10 displays the product ID number. This is because the product entity class contains a method that uses an eager fetch to generate a sequence of numbers for the prodId
attribute. This populates the value as the row is created.
However, if instead you've configured the attribute's type to DBSequence (which uses a database trigger to generate the sequence), the number would not be populated until the object is committed to the database. In this case, the user would see a negative number as a placeholder. To avoid this, you can use the following EL expression for the Rendered
attribute of the input text field:
#{bindings.EmployeeId.inputValue.value > 0}
This expression will display the component only when the value is greater than zero, which will not be the case before it is committed. Similarly, you can simply set the Rendered
attribute to false
. However, then the page will never display the input text field component for the primary key.
If the Commit button for the input form does not cause the user to navigate off the page, the page re-renders displaying the data from the last entry. This is because the refreshCondition
on the invokeCreate
invoke action (${!adfFacesContext.postback and empty bindings.exceptionsList}
) causes the action to not be invoked when there is a postback, which is the case when committing the data.
If you want users to be able to stay on the page (for example to create more than one product at a time), you need to change the refreshCondition
so that it will allow the invokeCreate
action to execute after committing a new object. To do this, you use the setActionListener
component within the Commit command component. The setActionListener
component allows the command component to set a value before navigating. In this case, the command component will set a flag (named createAnother
) on the request scope to true
. The refreshCondition
can then evaluate this flag to determine whether or not to execute the invokeCreate
action, as shown in the following procedure. For more information about the setActionListener
component, see Section 17.4.2, "What Happens When You Set Parameters".
To create an input form that can create multiple objects:
Follow the procedure to create an input form.
On the JSF page, drag a setActionListener
component from the Component Palette onto the Commit command button.
Note: This procedure assumes that the user will click this Commit button and return to the same page to create another entry. You may wish to change the name of the button to reflect that, for example, Commit and Create Another. You will need to create a different button to navigate off the page. |
In the Insert setActionListener dialog, set the following:
From: #{true}
To: #{requestScope.createAnother}
This creates a flag named createAnother
on the request scope, and sets it to true
.
Open the page definition for the JSF page.
Change the refreshCondition
for the invokeCreate
invoke action from
${!adfFacesContext.postback and empty bindings.exceptionsList}
to:
#{empty bindings.expressionList and (!adfFacesContext.postback or requestScope.createAnother)}
This sets the condition to execute the invokeCreate
action when the expression list that contains error messages is empty, and there was not or postback or the createAnother
flag on the request scope is set to true.
Note: ThesetActionListener component executes during the Invoke Application phase of the lifecycle. Therefore, the refresh attribute for the invokeCreate action must be set to a subsequent phase. In this case, it is set to renderModel by default, and should not be changed. |