Oracle® Fusion Middleware Java EE Developer's Guide for Oracle Application Development Framework 11g Release 1 (11.1.1.4.0) E16272-02 |
|
![]() Previous |
![]() Next |
This chapter describes how to use the Data Controls panel to create databound forms using ADF Faces components.
This chapter includes the following sections:
Section 3.1, "Introduction to Creating a Basic Databound Page"
Section 3.5, "Creating a Form Using a Method That Takes Parameters"
Section 3.8, "Using a Dynamic Form to Determine Data to Display at Runtime"
Section 3.9, "Modifying the UI Components and Bindings on a Form"
You can create UI pages that allow you to display and collect information using data controls created for your business services. For example, using the Data Controls panel, you can drag an attribute for an item, and then choose to display the value either as read-only text or as an input text field with a label. JDeveloper creates all the necessary JSF tag and binding code needed to display and update the associated data. For more information about the Data Controls panel and the declarative binding experience, see Chapter 2, "Using ADF Model Data Binding in a Java EE Web Application."
Instead of having to drop individual attributes, JDeveloper allows you to drop all attributes for an object at once as a form. The actual UI components that make up the form depend on the type of form dropped. You can create forms that display values, forms that allow users to edit values, and forms that collect values (input forms).
For example, the Suppliers module contains a page that allows users to view and edit information about a supplier, as shown in Figure 3-1. This form was created by dragging and dropping the supplierFindAll
accessor collection from the Data Controls panel.
Once you create the UI components, you can then drop built-in operations as command UI components that allow you to navigate through the records in a collection or that allow users to operate on the data. For example, you can create a button that allows users to delete data objects displayed in the form. You can also modify the default components to suit your needs.
JDeveloper allows you to create text fields declaratively in a WYSIWYG development environment for your JSF pages, meaning you can design most aspects of your pages without needing to look at the code. When you drag and drop items from the Data Controls panel, JDeveloper declaratively binds ADF Faces text UI components to attributes on a data control using an attribute binding.
To create a text field that can display or update an attribute, you drag and drop an attribute of a collection from the Data Controls panel.
To create a bound text field:
From the Data Controls panel, select an attribute for a collection. For a description of the icons that represent attributes and other objects in the Data Controls panel, see Table 2-1.
For example, Figure 3-2 shows the address1
attribute under the addressFindAll
accessor collection of the SupplierFacedLocal
data control in the Supplier module. This is the attribute to drop to display or enter the first part of an address.
Drag the attribute onto the page, and from the context menu choose the type of widget to display or collect the attribute value. For an attribute, you are given the following choices:
Text:
ADF Input Text w/ Label: Creates an ADF Faces inputText
component with a nested validator
component. The label
attribute is populated.
Tip: For more information about validators and other attributes of theinputText component, see the "Using Input Components and Defining Forms" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. |
ADF Input Text: Creates an ADF Faces inputText
component with a nested validator
component. The label
attribute is not populated.
ADF Output Text w/ Label: Creates a panelLabelAndMessage
component that holds an ADF Faces outputText
component. The label
attribute on the panelLabelAndMessage
component is populated.
ADF Output Text: Creates an ADF Faces outputText
component. No label is created.
ADF Output Formatted w/Label: Same as ADF Output Text w/Label, but uses an outputFormatted
component instead of an outputText
component. The outputFormatted
component allows you to add a limited amount of HTML formatting. For more information, see the "Displaying Output Text and Formatted Output Text" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework
ADF Output Formatted: Same as ADF Output Formatted w/Label, but without the label.
ADF Label: An ADF Faces outputLabel
component.
Single Selections: Creates single selection lists. For more information about creating lists on a JSF page, see Chapter 6, "Creating Databound Selection Lists."
For the purposes of this chapter, only the text components (and not the lists) will be discussed.
When you drag an attribute onto a JSF page and drop it as a UI component, among other things, a page definition file is created for the page (if one does not already exist). For a complete account of what happens when you drag an attribute onto a page, see Section 2.3.2, "What Happens When You Use the Data Controls Panel to Create UI Components." Bindings for the iterator and attributes are created and added to the page definition file. Additionally, the necessary JSPX page code for the UI component is added to the JSF page.
Whenever you create UI components on a page by dropping an item that is part of a collection from the Data Controls panel (or you drop the whole collection as a form or table), JDeveloper creates an iterator binding if it does not already exist. An iterator binding references an iterator for the data collection, which facilitates iterating over its data objects. It also manages currency and state for the data objects in the collection. An iterator binding does not actually access the data. Instead, it simply exposes the object that can access the data and it specifies the current data object in the collection. Other bindings then refer to the iterator binding in order to return data for the current object or to perform an action on the object's data. Note that the iterator binding is not an iterator. It is a binding to an iterator.
For example, if you drop the address1
attribute under the addressFindAll
collection, JDeveloper creates an iterator binding for the SupplierFacadeLocal
data control and an accessorIterator
binding for the addressFindAll
accessor, which in turn has the SupplierFacadeLocal iterator as its master binding.
Tip: There is one accessor iterator binding created for each collection returned from an accessor. This means that when you drop two attributes from the same accessor (or drop the attribute twice), they use the same binding. This is fine, unless you need the binding to behave differently for the different components. In that case, you will need to manually create separate iterator bindings. |
The iterator binding's rangeSize
attribute determines how many rows of data are fetched from a data control each time the iterator binding is accessed. This attribute gives you a relative set of 1-n rows positioned at some absolute starting location in the overall row set. By default, the attribute is set to 25
. Example 3-1 shows the iterator bindings created when you drop an attribute from the addressFindAll
accessor collection.
Example 3-1 Page Definition Code for an Iterator Accessor Binding
<executables> <iterator Binds="root" RangeSize="25" DataControl="SupplierFacadeLocal" id="SupplierFacadeLocalIterator"/> <accessorIterator MasterBinding="SupplierFacadeLocalIterator" Binds="addressesFindAll" RangeSize="25" DataControl="SupplierFacadeLocal" BeanClass="oracle.fodemo.supplier.model.Addresses" id="addressesFindAllIterator"/> </executables>
This metadata allows the ADF binding container to access the attribute values. Because the iterator binding is an executable, by default it is invoked when the page is loaded, thereby allowing the iterator to access and iterate over the collection returned by the addressFindAll
accessor. This means that the iterator will manage all the objects in the collection, including determining the current row in the collection or determining a range of address objects.
When you drop an attribute from the Data Controls panel, JDeveloper creates an attribute binding that is used to bind the UI component to the attribute's value. This type of binding presents the value of an attribute for a single object in the current row in the collection. Value bindings can be used both to display and to collect attribute values.
For example, if you drop the address
1 attribute under the addressFindAll
accessor as an ADF Output Text w/Label widget onto a page, JDeveloper creates an attribute binding for the address1
attribute. This allows the binding to access the attribute value of the current record. Example 3-2 shows the attribute binding for address1
created when you drop the attribute from the addressFindAll
accessor. Note that the attribute value references the iterator named addressesFindAllIterator
.
Example 3-2 Page Definition Code for an Attribute Binding
<bindings> <attributeValues IterBinding="addressesFindAllIterator" id="address1"> <AttrNames> <Item Value="address1"/> </AttrNames> </attributeValues </bindings>
For information regarding the attribute binding element properties, see the "Oracle Binding Properties" appendix of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
When you create a text field by dropping an attribute from the Data Controls panel, JDeveloper creates the UI component associated with the widget dropped by writing the corresponding tag to the JSF page.
For example, when you drop the address1
attribute as an Output Text w/Label widget, JDeveloper inserts the tags for a panelLabelAndMessage
component and an outputText
component. It creates an EL expression that binds the label
attribute of the panelLabelAndMessage
component to the label
property of hints created for the address1
's binding. This expression evaluates to the label UI hint set in the Java object's structure XML file. It creates another expression that binds the outputText
component's value
attribute to the inputValue
property of the address1
binding, which evaluates to the value of the address1
attribute for the current row. An ID is also automatically generated for both components.
Tip: JDeveloper automatically generates IDs for all ADF Faces components. You can override these values as needed. |
Example 3-3 shows the code generated on the JSF page when you drop the address1
attribute as an Output Text w/Label widget.
Example 3-3 JSF Page Code for an Attribute Dropped as an Output Text w/Label
<af:panelLabelAndMessage label="#{bindings.address1.hints.label}" id="plam1"> <af:outputText value="#{bindings.address1.inputValue}" id="ot1"/> </af:panelLabelAndMessage>
If instead you drop the address1
attribute as an Input Text w/Label widget, JDeveloper creates an inputText
component. As Example 3-4 shows, similar to the output text component, the value is bound to the inputValue
property of the address1
binding. Additionally, the following properties are also set:
label
: Bound to the label
property of the control hint set on the object.
required
: Bound to the mandatory
property, which in turn references the isNotNull
property of the UI control hint.
columns
: Bound to the displayWidth
property of the control hint, which determines how wide the text box will be.
maximumLength
: Bound to the precision property of the control hint. This control hint property determines the maximum number of characters per line that can be entered into the field.
In addition, JDeveloper adds a validator component.
Example 3-4 JSF Page Code for an Attribute Dropped as an Input Text w/Label
<af:inputText value="#{bindings.address1.inputValue}" label="#{bindings.address1.hints.label}" required="#{bindings.address1.hints.mandatory}" columns="#{bindings.address1.hints.displayWidth}" maximumLength="#{bindings.address1.hints.precision}"> shortDesc="#{bindings.address1.hints.tooltip}" id="it1"> <f:validator binding="#{bindings.address1.validator}"/> </af:inputText>
You can change any of these values to suit your needs. For example, the isNotNull
control hint on the structure file is set to false
by default, which means that the required
attribute on the component will evaluate to false
as well. You can override this value by setting the required
attribute on the component to true
. If you decide that all instances of the attribute should be mandatory, then you can change the control hint in the structure file, and all instances will be required. For more information about these properties, see Section 2.3.2, "What Happens When You Use the Data Controls Panel to Create UI Components."
Instead of dropping each of the individual attributes of a collection to create a form, you can create a complete form that displays or collects data for all the attributes on an object. For example, the form on the Edit Suppliers Details page was created by dropping the productFindAll
accessor collection from the Data Controls panel.
You can also create forms that provide more functionality than simply displaying data from a collection. For information about creating a form that allows a user to update data, see Section 3.6, "Creating a Form to Edit an Existing Record." For information about creating forms that allow users to create a new object for the collection, see Section 3.7, "Creating an Input Form." You can also create search forms. For more information, see Chapter 7, "Creating Databound Search Forms."
To create a form using a data control, you bind the UI components to the attributes on the corresponding object in the data control. JDeveloper allows you to do this declaratively by dragging and dropping a returned collection from the Data Controls panel.
To create a basic form:
From the Data Controls panel, select the collection that returns the data you wish to display. Figure 3-3 shows the productFindAll
accessor returned collection.
Drag the collection onto the page, and from the context menu choose the type of form that will be used to display or collect data for the object. For a form, you are given the following choices:
ADF Form: Launches the Edit Form Fields dialog that allows you to select individual attributes instead of having JDeveloper create a field for every attribute by default. It also allows you to select the label and UI component used for each attribute. By default, ADF inputText
components are used for most attributes. Each inputText
component has the label
attribute populated.
Attributes that are dates use the InputDate
component. Additionally, if a control hint has been created for an attribute, or if the attribute has been configured to be a list, then the component set by the hint is used instead. InputText
components contain a validator tag that allows you to set up validation for the attribute, and if the attribute is a number or a date, a converter is also included.
Tip: For more information about validators, converters, and other attributes of theinputText component, see the "Using Input Components and Defining Forms" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. |
ADF Read-Only Form: Same as the ADF Form, but read-only outputText
components are used. Since the form is meant to display data, no validator
tags are added (converters are included). Attributes of type Date
use the outputText
component when in a read-only form. All components are placed inside panelLabelAndMessage
components, which have the label
attribute populated. The panelLabelAndMessage
components are placed inside a panelFormLayout
component.
ADF Dynamic Form: Creates a form whose bindings are determined at runtime. For more information, see Section 3.8, "Using a Dynamic Form to Determine Data to Display at Runtime."
In the Edit Form Fields dialog, configure your form.
You can elect to include navigational controls that allow users to navigate through all the data objects in the collection. For more information, see Section 3.4, "Incorporating Range Navigation into Forms." You can also include a Submit button used to submit the form. This button submits the HTML form and applies the data in the form to the bindings as part of the JSF/ADF page lifecycle. For additional help in using the dialog, click Help. All UI components are placed inside a panelFormLayout
component.
If you are building a form that allows users to update data, you now need to drag and drop a method that will perform the update. For more information, see Section 3.6, "Creating a Form to Edit an Existing Record."
Dropping an object as a form from the Data Controls panel has the same effect as dropping a single attribute, except that multiple attribute bindings and associated UI components are created. The attributes on the UI components (such as value
) are bound to properties on that attribute's binding object (such as inputValue
) or to the values of control hints set on the corresponding service. Example 3-5 shows some of the code generated on the JSF page when you drop the suppliersFindAll
accessor collection as a default ADF form to create the Edit Suppliers Details form.
Note: If an attribute is marked as hidden on the associated structure definition file, then no corresponding UI is created for it. |
Example 3-5 Code on a JSF Page for an Input Form
<af:panelFormLayout id="pfl1"> <af:inputText value="#{bindings.supplierName.inputValue}" label="#{bindings.supplierName.hints.label}" required="#{bindings.supplierName.hints.mandatory}" columns="#{bindings.supplierName.hints.displayWidth}" maximumLength="#{bindings.supplierName.hints.precision}" shortDesc="#{bindings.supplierName.hints.tooltip}" id="it4"> <f:validator binding="#{bindings.supplierName.validator}"/> </af:inputText> <af:inputText value="#{bindings.email.inputValue}" label="#{bindings.email.hints.label}" required="#{bindings.email.hints.mandatory}" columns="#{bindings.email.hints.displayWidth}" maximumLength="#{bindings.email.hints.precision}" shortDesc="#{bindings.email.hints.tooltip}" id="it3"> <f:validator binding="#{bindings.email.validator}"/> </af:inputText> <af:inputText value="#{bindings.phoneNumber.inputValue}" label="#{bindings.phoneNumber.hints.label}" required="#{bindings.phoneNumber.hints.mandatory}" columns="#{bindings.phoneNumber.hints.displayWidth}" maximumLength="#{bindings.phoneNumber.hints.precision}" shortDesc="#{bindings.phoneNumber.hints.tooltip}" id="it1"> <f:validator binding="#{bindings.phoneNumber.validator}"/> </af:inputText> <af:inputText value="#{bindings.supplierStatus.inputValue}" label="#{bindings.supplierStatus.hints.label}" required="#{bindings.supplierStatus.hints.mandatory}" columns="#{bindings.supplierStatus.hints.displayWidth}" maximumLength="#{bindings.supplierStatus.hints.precision}" shortDesc="#{bindings.supplierStatus.hints.tooltip}" id="it2"> <f:validator binding="#{bindings.supplierStatus.validator}"/> </af:inputText> . . . </af:panelFormLayout>
Note: For information regarding the validator and converter tags, see the "Validating and Converting Input" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. |
When you create an ADF Form, if you elect to include navigational controls, JDeveloper includes ADF Faces command components bound to existing navigational logic on the data control. This built-in logic allows the user to navigate through all the data objects in the collection. For example, Figure 3-4 shows a form that would be created if you dragged the suppliersFindAll
accessor and dropped it as an ADF Form that uses navigation.
By default, when you choose to include navigation when creating a form using the Data Controls panel, JDeveloper creates First, Last, Previous, and Next buttons that allow the user to navigate within the collection.
You can also add navigation buttons to an existing form manually.
To manually add navigation buttons:
From the Data Controls panel, select the operation associated with the collection of objects on which you wish the operation to execute, and drag it onto the JSF page.
For example, if you want to navigate through a collection of products, you would drag the Next operation associated with the suppliersFindAll
accessor. Figure 3-5 shows the operations associated with the suppliersFindAll
accessor.
From the ensuing context menu, choose either ADF Button or ADF Link.
Tip: You can also drop the First, Previous, Next, and Last buttons at once. To do so, drag the corresponding collection, and from the context menu, choose Navigation > ADF Navigation Buttons. |
When you drop any operation as a command component, JDeveloper:
Defines an action binding in the page definition file for the associated operations
Configures the iterator binding to use partial page rendering for the collection
Inserts code in the JSF page for the command components
Action bindings execute business logic. For example, they can invoke built-in methods on the action binding object. These built-in methods operate on the iterator or on the data control itself, and are represented as operations in the Data Controls panel. JDeveloper provides navigation operations that allow users to navigate forward, backwards, to the first object in the collection, and to the last object.
Like value bindings, action bindings for operations contain a reference to the iterator binding when the action binding is bound to one of the iterator-level actions, such as Next
or Previous
. These types of actions are performed by the iterator, which determines the current object and can therefore determine the correct object to display when a navigation button is clicked.
Action bindings use the RequiresUpdateModel
property, which determines whether or not the model needs to be updated before the action is executed. In the case of navigation operations, by default this property is set to true
, which means that any changes made at the view layer must be moved to the model before navigation can occur. Example 3-6 shows the action bindings for the navigation operations.
Example 3-6 Page Definition Code for an Operation Action Binding
<action IterBinding="CustomerInfoVO1Iterator" id="First" RequiresUpdateModel="true" Action="first"/> <action IterBinding="CustomerInfoVO1Iterator" id="Previous" RequiresUpdateModel="true" Action="previous"/> <action IterBinding="CustomerInfoVO1Iterator" id="Next" RequiresUpdateModel="true" Action="next"/> <action IterBinding="CustomerInfoVO1Iterator" id="Last" RequiresUpdateModel="true" Action="last"/>
Iterator bindings have a rangeSize
attribute that the binding uses to determine the number of data objects to make available for the page for each iteration. This attribute helps in situations when the number of objects in the data source is quite large. Instead of returning all objects, the iterator binding returns only a set number, which then become accessible to the other bindings. Once the iterator reaches the end of the range, it accesses the next set. Example 3-7 shows the default range size for the suppliersFindAll
iterator.
Example 3-7 RangeSize Attribute for an Iterator
<accessorIterator MasterBinding="SessionEJBLocalIterator"
Binds="suppliersFindAll" RangeSize="25"
DataControl="SessionEJBLocal" BeanClass="model.Suppliers"
id="suppliersFindAllIterator" ChangeEventPolicy="ppr"/>
Note: ThisrangeSize attribute is not the same as the rows attribute on a table component. |
By default, the rangeSize
attribute is set to 25
. This means that a user can view 25 objects, navigating back and forth between them, without needing to access the data source. The iterator keeps track of the current object. Once a user clicks a button that requires a new range (for example, clicking the Next button on object number 25), the binding object executes its associated method against the iterator, and the iterator retrieves another set of 25 records. The bindings then work with that set. You can change this setting as needed. You can set it to -1
to have the full record set returned.
Note: When you create a navigable form using the Data Controls panel, theCacheResults property on the associated iterator is set to true . This ensures that the iterator's state, including currency information, is cached between requests, allowing it to determine the current object. If this property is set to false , navigation will not work. |
Table 3-1 shows the built-in navigation operations provided on data controls and the result of invoking the operation or executing an event bound to the operation. For more information about action events, see the "What Happens at Runtime: How Action Events and Action Listeners Work" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Table 3-1 Built-in Navigation Operations
Operation | When invoked, the associated iterator binding will... |
---|---|
First |
Move its current pointer to the beginning of the result set. |
Last |
Move its current pointer to the end of the result set. |
Previous |
Move its current pointer to the preceding object in the result set. If this object is outside the current range, the range is scrolled backward a number of objects equal to the range size. |
Next |
Move its current pointer to the next object in the result set. If this object is outside the current range, the range is scrolled forward a number of objects equal to the range size. |
Previous Set |
Move the range backward a number of objects equal to the range size attribute. |
Next Set |
Move the range forward a number of objects equal to the range size attribute. |
When you create command components using navigation operations, the command components are placed in a panelGroupLayout
component. JDeveloper creates an EL expression that binds a navigational command button's actionListener
attribute to the execute
property of the action binding for the given operation.
At runtime an action binding will be an instance of the FacesCtrlActionBinding
class, which extends the core JUCtrlActionBinding
implementation class. The FacesCtrlActionBinding
class adds the following methods:
public void execute(ActionEvent event)
: This is the method that is referenced in the actionListener
property, for example #{bindings.First.execute}
.
This expression causes the binding's operation to be invoked on the iterator when a user clicks the button. For example, the First command button's actionListener
attribute is bound to the execute
method on the First
action binding.
public String outcome()
: This can be referenced in an Action
property, for example #{bindings.Next.outcome}
.
This can be used for the result of a method action binding (once converted to a String
) as a JSF navigation outcome to determine the next page to navigate to.
Note: Using the outcome method on the action binding implies tying the view-controller layer too tightly to the model, so it should rarely be used. |
Every action binding for an operation has an enabled
boolean property that Oracle ADF sets to false
when the operation should not be invoked. By default, JDeveloper binds the UI component's disabled
attribute to this value to determine whether or not the component should be enabled. For example, the UI component for the First button has the following as the value for its disabled
attribute:
#{!bindings.First.enabled}
This expression evaluates to true
whenever the binding is not enabled, that is, when the operation should not be invoked, thereby disabling the button. In this example, because the framework will set the enabled
property on the binding to false
whenever the first record is being shown, the First button will automatically be disabled because its disabled
attribute is set to be true
whenever enabled
is False
. For more information about the enabled
property, see the "Oracle ADF Binding Properties" appendix of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Example 3-8 shows the code generated on the JSF page for navigation operation buttons. For more information about the partialSubmit
attribute on the button, see the "Enabling Partial Page Rendering Declaratively" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. For information about automatic partial page rendering for the binding, see the "What You May Need to Know About Automatic Partial Page Rendering" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Example 3-8 JSF Code for Navigation Buttons Bound to ADF Operations
<f:facet name="footer"> <af:panelGroupLayout> <af:commandButton actionListener="#{bindings.First.execute}" text="First" disabled="#{!bindings.First.enabled}" partialSubmit="true" id="cb1"/> <af:commandButton actionListener="#{bindings.Previous.execute}" text="Previous" disabled="#{!bindings.Previous.enabled}" partialSubmit="true" id="cb2"/> <af:commandButton actionListener="#{bindings.Next.execute}" text="Next" disabled="#{!bindings.Next.enabled}" partialSubmit="true" id="cb3"/> <af:commandButton actionListener="#{bindings.Last.execute}" text="Last" disabled="#{!bindings.Last.enabled}" partialSubmit="true" id="cb4"/> </af:panelGroupLayoutr> </f:facet>
There may be cases where a page needs information before it can display content. For these types of pages, you create the form using a returned collection from a method that takes parameters. The requesting page needs to supply the value of the parameters in order for the method to execute.
For example, the form on the productInfo
page is created using the returned collection from the findProductById(Long)
method. Instead of returning all products, it returns only the product the user selected on the previous page. The toolbar button on the previous page sets the parameter (Long
), which provides the product's ID. For more information about using a command component to set a parameter value, see Section 3.5.4, "What You May Need to Know About Setting Parameters with Methods."
To create forms that require parameters, you must be able to access the values for the parameters in order to determine the record(s) to return. You access those values by adding logic to a command button on another page that will set the parameter value on some object that the method can then access. For example, on the browse.jspx
page, the Edit toolbar button sets the product ID in the pageFlow
scope. To create the form showing the product information, you use the return of the findProductById(Long)
method, and you have that method access the parameter on the pageFlow
scope, where it is stored.
Before you begin:
You need to create a method on your session bean that will return the items needed to be displayed in your form. For example, the findProductById(Long)
method was added to the SupplierFacadeBean.java
class.
Tip: You need to refresh the Data Controls panel in order for any changes made to services to display in the panel. To refresh the panel, click the Refresh icon. |
To create a form or table that uses parameters:
From the Data Controls panel, drag a collection that is a return of a method that takes a parameter or parameters and drop it as any type of form.
For example, to create the form that displays when you click the toolbar button to edit a product, you would drag and drop the Product return, as shown in Figure 3-6.
In the Edit Form Fields dialog, configure the form as needed and click OK.
For help in using the dialogs, click Help.
Because the method takes parameters, the Edit Action Binding dialog opens, asking you to set the value of the parameters.
In the Action Binding Editor, enter the value for each parameter by clicking the browse (...) icon in the Value field to open the EL Expression Builder. Select the node that represents the value for the parameter.
For example, the toolbar button uses a setActionListenerComponent
that sets the productId
parameter value on the pageFlow
scope. To access that value, you would use #{pageFlowScope.ProductId}
as the value for the parameter.
This editor uses the value to create the NamedData
element that will represent the parameter when the method is executed. Since you are dropping a collection that is a return of the method (unlike a method bound to a command button), this method will be run when the associated iterator is executed as the page is loaded. You want the parameter value to be set before the page is rendered. This means the NamedData
element needs to get this value from wherever the sending page has set it.
When you use a return of a method that takes parameters to create a form, JDeveloper:
Creates an action binding for the method, a method iterator binding for the result of the method, and attribute bindings for each of the attributes of the object, or in the case of a table, a table binding. It also creates NamedData
elements for each parameter needed by the method.
Inserts code in the JSF page for the form using ADF Faces components.
Example 3-9 shows the action method binding created when you drop the findProductById(Long)
method, where the value for the productId
was set to the ProductId
attribute stored in pageFlow
Scope
.
Example 3-9 Method Action Binding for a Method Return
<bindings> <methodAction id="findProductById" RequiresUpdateModel="true" Action="invokeMethod" MethodName="findProductById" IsViewObjectMethod="false" DataControl="SupplierFacadeLocal" InstanceName="SupplierFacadeLocal.dataProvider" ReturnName="SupplierFacadeLocal.methodResults.findProductById_ SupplierFacadeLocal_dataProvider_findProductById_result"> <NamedData NDName="productId" NDValue="#{pageFlowScope.ProductId}" NDType="java.lang.Long"/> </methodAction> ... </bindings>
Note that the NamedData
element will evaluate to productID
on the pageFlow
Scope
, as set by any requesting page.
Unlike a method executed when a user clicks a command button, a method used to create a form is executed as the page is loaded. When the method is executed in order to return the data for the page, the method evaluates the EL expression for the NamedData
element and uses that value as its parameter. It is then able to return the correct data. If the method takes more than one parameter, each is evaluated in turn to set the parameters for the method.
For example, when the ProductInfo
page loads, it takes the value of the ProductId
parameter on the pageFlow
scope, and sets it as the value of the parameter needed by the findProductById(Integer)
method. Once that method executes, it returns only the record that matches the value of the parameter. Because you dropped the return of the method to create the form, that return is the product that is displayed.
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 command button on one page that will navigate to another page, but a component on the resulting page will display only if the 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. A setPropertyListener
component with the type
property set to action
, which is nested in the command button, is then used to set parameter. For more information about setting parameters using methods, see the "Setting Parameter Values Using a Command Component" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Note: If you are using task flows, you can use the task flow parameter passing mechanism. For more information, see the "Using Parameters in Task Flows" chapter of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework. |
Often a page or a region within a page needs information from somewhere else on the page or from a different region (for more information about regions, see the "Using Task Flows as Regions" sections of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework). While you can pass parameters to obtain that information, doing so makes sense only when the parameters are well known and the inputs are EL-accessible to the page. Parameters are also useful when a task flow may need to be restarted if the parameter value changes.
However, suppose you have a task flow with multiple page fragments that contain various interesting values that could be used as input on one of the pages in the flow. If you were to use parameters to pass the value, the task flow would need to surface output parameters for the union of each of the interesting values on each and every fragment. Instead, for each fragment that contains the needed information, you can define a contextual event that will be raised when the page is submitted. The page or fragment that requires the information can then subscribe to the various events and receive the information through the event.
You can create and configure contextual events using a page definition file. For more information, see the "Creating Contextual Events" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
You can create a form that allows a user to edit the current data, and then commit those changes to the data source. To do this, you use methods that can modify data records associated with the collection to create command buttons. For example, you can use the default mergeSuppliers(Suppliers)
method to create a button that allows a user to update a supplier.
If the page is not part of a bounded task flow, you need to use the merge or persist method associated with the collection to merge the changes back into the collection (for more information about the difference between the two, see Section 3.6.3, "What You May Need to Know About the Difference Between the Merge and Persist Methods"). If the page is part of a transaction within a bounded task flow, you use the commit
and rollback
operations to resolve the transaction in a task flow return activity. For more information, see the "Using Task Flow Return Activities" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
To use methods on a form, you follow the same procedures as with the operations.
To create an edit form:
From the Data Controls panel, drag the collection for which you wish to create the form, and choose ADF Form from the context menu.
This creates a form using inputText
components, which will allow the user to edit the data in the fields.
From the Data Controls panel, select the merge or persist method associated with the collection of objects on which you wish the operation to execute, and drag it onto the JSF page.
For example, if you want to be able to update a supplier record and will not be working with that instance again, you would drag the mergeSuppliers(Suppliers)
method. For more information about the difference between the merge and persist methods, see Section 3.6.3, "What You May Need to Know About the Difference Between the Merge and Persist Methods."
From the ensuing context menu, choose either ADF Button or ADF Link.
In the Edit Action Binding dialog, you need to populate the value for the method's parameter. For the merge methods (and the other default methods), this is the object being updated.
In the Parameters section, use the Value dropdown list to select Show EL Expression Builder.
In the Expression Builder, expand the node for the accessor's iterator, then expand the currentRow node, and select dataProvider.
This will create an EL expression that evaluates to the data for the current row in the accessor's iterator.
Click OK.
For example, if you created a form using the suppliersFindAll
accessor collection, then JDeveloper would have created an accessorIterator
binding named suppliersFindAllIterator
. You would need to select the dataProvider
for the current row under that iterator, as shown in Figure 3-7. This reference means that the parameter value will resolve to the value of the row currently being shown in the form.
Note: If the page is part of a transaction within a bounded task flow, then instead of creating a button from the merge method (or other default method), you would set that method as the value for the transaction resolution when creating the task flow return activity. For more information, see the "Using Task Flow Return Activities" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework. |
When you drop a method as a command button, JDeveloper:
Defines a method binding for the method. If the method takes any parameters, JDeveloper creates NamedData
elements that hold the parameter values. For more information about NamedData
elements, see Section 3.5.3, "What Happens at Runtime: Setting Parameters for a Method."
Inserts code in the JSF page for the ADF Faces command component. This code is the same as code for any other command button, as described in Section 3.6.2.2, "Using EL Expressions to Bind to Methods." However, instead of being bound to the execute
method of an action binding for an operation, the buttons are bound to the execute
method of the action binding for the method that was dropped.
Similar to when you create a button from a built-in operation, when you create a button from a method, JDeveloper creates an action binding for the method. Example 3-10 shows the action binding created when you drop the mergeSuppliers(Suppliers)
method.
Example 3-10 Page Definition Code for an Action Binding Used by the Iterator
<bindings> <methodAction id="mergeSuppliers" RequiresUpdateModel="true" Action="invokeMethod" MethodName="mergeSuppliers" IsViewObjectMethod="false" DataControl="SessionEJBLocal" InstanceName="SessionEJBLocal.dataProvider" ReturnName="SessionEJBLocal.methodResults.mergeSuppliers_ SessionEJBLocal_dataProvider_persistSuppliers_result"> <NamedData NDName="suppliers" NDType="model.Suppliers"/> </methodAction> </bindings>
In this example, when the binding is accessed, the method is invoked because the action property value is invokeMethod
.
When you drop a method that takes parameters onto a JSF page, JDeveloper also creates NamedData
elements for each parameter. These elements represent the parameters of the method. For example, the mergeSuppliers(Suppliers)
method action binding contains a NamedData
element for the Suppliers
parameter.
Like creating command buttons using navigation 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. This binding causes the binding's method to be invoked on the business service. For more information about the actionListener
attribute, see the "What Happens at Runtime: How Action Events and Action Listeners Work" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Tip: Instead of binding a button to theexecute method on the action binding, you can bind the button to a 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 3.6.4, "What You May Need to Know About 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 3-11 shows the EL expression used to bind the command button to the mergeSuppliers(Suppliers)
method.
Example 3-11 JSF Code to Bind a Command Button to a Method
<af:commandButton actionListener="#{bindings.mergeSupplier.execute}" text="mergeSupplier" disabled="#{!bindings.mergeSupplier.enabled}" id="cb1"/>
If when you created your session bean, you chose to expose the merge and persist methods for a structured object, then those methods appear in the Data Controls panel and you can use them to create buttons that allow the user to merge and persist the current instance of the object. Which you use depends on whether the page will need to interact with the instance once updates are made. If you want to be able to continue to work with the instance, then you need to use the persist method.
The merge methods are implementations of the JPA EntityManager.merge
method. This method takes the current instance, copies it, and passes the copy to the PersistenceContext
. It then returns a reference to that persisted entity and not to the original object. This means that any subsequent changes made to that instance will not be persisted unless the merge method is called again.
The persist methods are implementations of the JPA EntityManager.persist
method. Like the merge method, this method passes the current instance to the PersistenceContext
. However, the context continues to manage that instance so that any subsequent updates will be made to the instance in the context.
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. 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 more information, see the "Overriding Declarative Methods" section in the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
You can create a form that allows a user to enter information for a new record and then commit that record to the data source. You need to use a task flow that contains a method activity that will call the Create
operation before the page with the input form is displayed. This method activity causes a blank row to be inserted into the row set which the user can then populate using a form.
Tip: For more information about task flows, see the "Creating ADF Task Flows" part of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework. |
For example, in the Supplier module, you could create a new form that allows the user to create an address. You might create a create-address-task-flow
task flow that contains a createAddress
method activity, which calls the Create
operation on the addresses
accessor. Control is then passed to the createAddress
view activity, which displays a form where the user can enter a new address, as shown in Figure 3-8.
Note: If your application does not use task flows, then the calling page should invoke thecreate operation similar to the way in which a task flow's method activity would. For example, you could provide application logic within an event handler associated with a command button on the calling page. |
You create an input form within a bounded task flow to ensure proper transaction handling.
Before you begin:
You need to create a bounded task flow that will contain both the form and the method activity that will execute the Create
operation. The task flow should start a new transaction. For procedures, see the "Creating a Task Flow" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
To create an input form:
To the bounded task flow, add a method activity. Have this activity execute the Create
operation associated with the accessor for which you are creating the form. For these procedures on using method activities, see the "Using Method Call Activities" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
For example, to create the form that would allow users to create addresses, you would have the method activity execute the Create
operation associated with the addresses
accessor.
In the Property Inspector, enter a string for the fixed-outcome property. For example, you might enter create
as the fixed-outcome
value.
Add a view activity that represents the page for the input form. For information on adding view activities, see the "Using View Activities" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Add a control flow case from the method activity to the view activity. In the Property Inspector, enter the value of the fixed-outcome property of the method activity set in Step 2 as the value of the from-outcome
of the control flow case.
Open the page for the view activity in the design editor, and from the Data Controls panel, drag the collection for which the form will be used to create a new record, and choose ADF Form from the context menu.
For example, for the form to create addresses, you would drag the addresses
accessor collection from the Data Controls panel.
Tip: If you want the user to be able to create multiple entries before committing to the database, do the following:
|
In the task flow, add a return activity. This return activity must execute the commit operation on the data control. For these procedures, see the "Using Task Flow Return Activities" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Tip: If when you set the return activity to execute thecommit operation the activity shows an error, it is probably because the task flow itself is not set up to start a transaction. You need to set it to do so. For more information, see the "Managing Transactions" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework. |
Add a control flow case from the view activity to the return activity. Set the fixed-outcome
attribute to a text string. For example, you might set it to return
.
From the Component Palette, drag and drop a button or other command component that will be used to invoke the return activity. Set the action
attribute to the text string set as the fixed-outcome
created in Step 7.
When you use an ADF Form to create an input form, JDeveloper:
Creates an iterator binding for the accessor and an action binding for the Create
operation in the page definition for the method activity. The Create
operation is responsible for creating a row in the row set and populating the data source with the entered data. In the page definition for the page, JDeveloper creates an iterator binding for the returned collection and attribute bindings for each of the attributes of the object in the collection, as for any other form.
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, the form shown in Figure 3-8 might be displayed by clicking a "Create Address" link on the main page. This link then navigates to the form where you can input data for a new address. Once the address is created, and you click the Save button, you return to the main page. Figure 3-9 shows a create-address-task-flow
task flow with the newAddress
method activity.
Example 3-12 shows the page definition file for the method activity.
Example 3-12 Page Definition Code for a Creation Method Activity
<executables> <iterator Binds="root" RangeSize="25" DataControl="SupplierFacadeLocal" id="SupplierFacadeLocalIterator"/> <accessorIterator MasterBinding="SupplierFacadeLocalIterator" Binds="addresses" RangeSize="25" DataControl="SupplierFacadeLocal" BeanClass="oracle.fodemo.supplier.model.Addresses" id="addressesIterator"/> </executables> <bindings> <action IterBinding="addressesIterator" id="Create" RequiresUpdateModel="true" Action="createRow"/> </bindings>
When the newAddress
method activity is accessed, the Create
action binding is invoked, which executes the CreateInsertRow
operation, and a new blank instance for the collection is created. Note that during routing from the method activity to the view activity, the method activity's binding container skips validation for required attributes, allowing the blank instance to be displayed in the form on the page.
ADF Faces offers a library of dynamic components that includes dynamic form and dynamic table widgets that you can drop from the Data Controls panel. Dynamic components differ from standard components in that all the binding metadata is created at runtime. This dynamic building of the bindings allows you set display information using control hints for attributes on the entity, instead of configuring the information in the Edit Form Fields dialog as you drop the control onto the page. Then if you want to change how the data displays, you need only change it in the structure definition file, and all dynamic components bound to that Java object will change their display accordingly. With standard components, if you want to change any display attributes (such as the order or grouping of the attributes), you would need to change each page on which the data is displayed.
For example, in the Suppliers module, you could set the category and field order attribute hints on the Suppliers
Java object that groups the supplierName
and supplierID
attributes together and at the top of a form (or at the leftmost columns of a table), the supplierStatus
at the bottom of a form (or the rightmost columns of a table), and the email
and phoneNumber
together and at the middle of a form or table.
Figure 3-10 shows a dynamic form at runtime created by dragging and dropping the Supplier
collection with control hints set in this manner.
To use dynamic forms you first need to set control hints (especially the order and grouping hints) on the structure file for the corresponding Java objects. Next you import the libraries for the dynamic components. You can then drop the dynamic form or table widgets onto your page.
Before you begin:
You need to set the category and field order control hints on the attributes in the structure file for the associated Java object.
For example, for the dynamic form in Figure 3-10, you would set the category and field order control hints for the supplierId
, supplierName
, phoneNumber
, email
, and supplierStatus
attributes, as follows:
Enter a String
for the Category field.
Use this same String
for the Category value for any other attribute that you want to appear with this attribute in a group. For example, the Category value for both the phoneNumber
and email
attributes is contact
.
Enter a number for the Field Order field that represents where in the group this attribute should appear.
For example, the phoneNumber
has a Field Order value of 1
and the email
attribute has a value of 2
.
For procedures on creating control hints, see the "Defining Attribute Control Hints for View Objects" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
To use dynamic components:
If not already included, import the dynamic component library.
In the Application Navigator, right-click the view project in which the dynamic components will be used, and from the context menu, choose Project Properties.
In the Project Properties dialog, select the JSP Tag Libraries node.
On the JSP Tag Libraries page, click Add.
In the Choose Tag Libraries dialog, select ADF Dynamic Components and click OK.
On the JSP Tag Libraries page, click OK.
From the Data Controls panel, drag the collection onto the page, and from the context menu, choose Forms > ADF Dynamic Form.
Tip: If dynamic components are not listed, then the library was not imported into the project. Repeat Step 1. |
In the Property Inspector, enter the following: for the Category field:
Category: Enter the string used as the value for the Category UI hint for the first group you'd like to display in your form. For example, in Figure 3-10, the Category value would be id
.
Editable: Enter true
if you want the data to be editable (the default). Enter false
if the data should be read-only.
Repeat Steps 6 and 7 for each group that you want to display on the form. For example, the form in Figure 3-10 is actually made up of three different forms: one for the category id
, one for the category contact
, and one for the category status
.
When you drop a dynamic form, only a binding to the iterator is created. Example 3-13 shows the page definition for a page that contains one dynamic form component created by dropping the supplier
collection. Note that no attribute bindings are created.
Example 3-13 Page Definition Code for a Dynamic Form
<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel" version="11.1.1.53.2" id="DynamicFormPageDef" Package="package.pageDefs"> <parameters/> <executables> <iterator Binds="root" RangeSize="25" DataControl="SupplierFacadeLocal" id="SupplierFacadeLocalIterator"/> <accessorIterator MasterBinding="SupplierFacadeLocalIterator" Binds="supplier" RangeSize="25" DataControl="SupplierFacadeLocal" BeanClass="oracle.fodemo.supplier.model.Supplier" id="supplierIterator"/> </executables> <bindings/> </pageDefinition>
JDeveloper inserts a form
tag which contains a dynamic form tag for each of the forms dropped. The form tag's value is bound to the iterator binding, as shown in Example 3-14. This binding means the entire form is bound to the data returned by the iterator. You cannot set display properties for each attribute individuality, nor can you rearrange attributes directly on the JSF page.
Example 3-14 JSF Page Code for a Dynamic Form
<af:document> <af:messages/> <af:form> <dynamic:form value="#{bindings.supplierIterator}" id="f1" category="id"/> <dynamic:form value="#{bindings.supplierIterator}" id="f2" category="contact"/> <dynamic:form value="#{bindings.supplierIterator}" id="f3" category="status"/> </af:form> </af:document>
Tip: You can set certain properties that affect the functionality of the form. For example, you can make a form available for upload, set the rendered property, or set a partial trigger. To do this, select theaf:form tag in the Structure window, and set the needed properties using the Property Inspector. |
When a page with dynamic components is rendered, the bindings are created just as they are when items are dropped from the Data Controls panel at design time, except that they are created at runtime. For more information, see Section 3.3.2, "What Happens When You Create a Form."
Tip: While there is a slight performance hit because the bindings need to be created at runtime, there is also a performance gain because the JSF pages do not need to be regenerated and recompiled when the structure of the view object changes. |
Once you use the Data Controls panel to create any type of form (except a dynamic form), you can then delete attributes, change the order in which they are displayed, change the component used to display data, and change the attribute to which the components are bound.
For more information about modifying existing UI components and bindings, see the "Modifying the UI Components and Bindings on a Form" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.