Skip Headers
Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3)
B25386-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

10.7 Creating an Input Form for a New Record

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.

10.7.1 How to Use Constructors to Create an Input Form

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.

Figure 10-8 Constructors in the Data Control Palette

Product, ExpertiseArea, and ServiceHistory constructors

To create an input form using a constructor:

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

  2. In the Edit Form Fields dialog, set the labels, bindings, and UI components. Do not select Include Submit Button.

  3. From the Data Control Palette, drag the persistEntity(Object) method. This method persists the object created by the constructor to the database.

  4. In the context menu, choose Methods > ADF Command Button.

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

    Figure 10-9 Result from the Product Constructor

    Result attribute under the Product action

Tip:

If you will be navigating to this page from another page that should display the newly created object when you return to it, you must set the cacheResults attribute on the iterator for the first page to false.

For example, say you have a page that lists all products, and a user can navigate from that page to another page to create a product. A button on this page both creates the product and navigates back to the list page. In order for the user to see the product just created, you must set the iterator binding for the product list to cacheResults=false. Doing so forces the iterator to reexecute when returning to the page and display the newly created product.


10.7.2 What Happens When You Use a Constructor

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.

Figure 10-10 A Simple Create Product Form

Create product form to enter ID, name, image and description

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.

10.7.3 How to Use a Custom Method to Create an Input Form

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:

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

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

10.7.4 What Happens When You Use Methods to Create a Parameter Form

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.

10.7.4.1 Using Variables and Parameters

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>

10.7.5 What Happens at Runtime

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.