Monday, February 1, 2010

How to Modify an InputText Field to a Choice List in Oracle ADF

Sometimes it just happends — either you didn't set it up correctly at beginning or you're asked to modify your UI component after a review. In this article, we'll describe such a case that we need to change a table column from af:inputText to af:selectOneChoice. Because the change is minor, we'll try to patch up existing codes without a full replacement.


The Problem

We have created a new table. However, we find out that it'll be more user friendly if we can change Investigation Status column from an input text field to a choice list (with fixed values such as: UNRESOLVED, COMMENTED, REVIEWED, BUG, and OK).

From the code level perspective, we want to change:

<af:inputText value="#{row.bindings.InvestigationStatus.inputValue}" autoSubmit="true"
  label="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.label}"
  required="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.mandatory}"
  columns="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.displayWidth}"
  maximumLength="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.precision}"
  shortDesc="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.tooltip}"
  id="it1">
<f:validator binding="#{row.bindings.InvestigationStatus.validator}"/>
</af:inputText>

to

<af:selectOneChoice value="#{row.bindings.InvestigationStatus.inputValue}"
    label="#{row.bindings.InvestigationStatus.label}"
    required="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.mandatory}"
    shortDesc="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.tooltip}"
    id="soc1" autoSubmit="true">
<f:selectItems value="#{row.bindings.InvestigationStatus.items}"
     id="si1"/>
</af:selectOneChoice>

After the changes, the final UI should look like below:


The Task


Most of the changes can be made declaratively with JDeveloper 11g. The steps of the task can be outlined as follows:
  1. Deleting original af:inputText
  2. Creating a new af:selectOneChoice
  3. Fixing old references existing in the partialTriggers
We'll describe each step in more details below. However, before you proceed, you may take some precautions:
  1. If you're using Source Code Control System, check in all pending changes. If not, it'll be a good idea to save the old contents of all files that get involved (i.e., jsff page and its page definition file).
  2. Although JDeveloper will try to find all usages of the changing components in the application for you and give warning before you make the changes, it'll still be a good idea to do a full search on the old compoenent ID in the application. If necessary, you can clean up references to old component manually although most of the time those remnants may cause no harm at all.
  3. Take notes on what get changes before and after. This could be a good learning experience and may add another eyes on finding possible mistakes.

Step 1 — Deleting original af:inputText

To delete original af:inputText:
  1. In the Application Navigator, double-click the page that contains the table definition.
  2. In the Structure view, expand the hierarchy to reveal the target column (i.e., af:column) and its child af:inputText.
  3. Right click af:inputText and select Delete.
  4. A Delete Safely Dialog will show up and says that usages were found. Click on Ignore because we're going to fix those usages in Step 3.

Step 2 — Creating a new af:selectOneChoice

To create a list bound to a fixed list of values:
  1. From the Data Controls panel, drag and drop the attribute (i.e., investigationStatus) onto the empty af:column in the Structure view and choose Create > Single Selections > ADF Select One Choice.
    The Edit List Binding dialog displays. The view object collection containing the attribute you dropped on the af:column is selected by default in the Base Data Source list.
  2. Select the Fixed List radio button.
    The Fixed List option lets end users choose a value from a static list that you define.
  3. In the Base Data Source Attribute list, choose an attribute (i.e., investigationStatus).
    The Base Data Source Attribute list contains all of the attributes in the view data collection you selected in the Base Data Source list.
  4. In the Set of Values box, enter each value you want to appear in the list. Press the 'Enter key to set a value before typing the next value. Note that if all your values are on the same line and separated by ",", it won't work because it will be treated as one single value.
    The order in which you enter the values is the order in which the list items are displayed in the SelectOneChoice control at runtime.
  5. Click OK.


Step 3 — Fixing old references existing in the partialTriggers

ADF Faces components can be set so that one component refreshes based on an interaction with another component, without the whole page needing to be refreshed. This is known as partial page rendering.

When a new value is selected from the list for Investigation Status field, we need to enable both Commit and Rollback buttons which were grayed out at beginning. In this case, our choice list need to be configured to be a trigger that cause both buttons to refresh and its autoSubmit property need to be set to true. These steps can be made declaratively via Property Inspector.

After the changes, target components should look like this:
<af:selectOneChoice value="#{row.bindings.InvestigationStatus.inputValue}"
       label="#{row.bindings.InvestigationStatus.label}"
       required="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.mandatory}"
       shortDesc="#{bindings.TestDetailForTestRun.hints.InvestigationStatus.tooltip}"
       id="soc1" autoSubmit="true">
<f:selectItems value="#{row.bindings.InvestigationStatus.items}"
        id="si1"/>
</af:selectOneChoice>

<af:commandToolbarButton text="Commit" id="ctb2"
  partialTriggers="ATt2:soc1 ATt2:it2"
  actionListener="#{bindings.Commit.execute}"
  disabled="#{!bindings.Commit.enabled}"/>
<af:commandToolbarButton text="Rollback" id="ctb3"
  partialTriggers="ATt2:soc1 ATt2:it2"
  actionListener="#{bindings.Rollback.execute}"
  disabled="#{!bindings.Rollback.enabled}"
  immediate="true">

References


  1. Simple AJAX-Style Partial Page Rendering (PPR) Example with AutoSubmit SelectOneChoice Control
  2. What You May Need to Know About Automatic Partial Page Rendering

No comments: