Oracle ADF UIX Developer's Guide | ![]() Contents |
![]() Previous |
![]() Next |
This chapter contains the following sections:
lovInput
elementlistOfValues
elementlovOpenWindowAction
Client ActionWeb pages frequently allow an end user to type in or update text data. Sometimes the input values are unbounded, and any user input is acceptable. However, the developer often needs to limit the user's input choices to a particular set of allowable values. This can be done using a radio buttons, check boxes, or pull-down lists. These elements work well when the number of choices is small, but they become cumbersome for large datasets.
When a large dataset is involved, the best way to present choices to the user is through a list of values (fondly referred to as an LOV). The list of values is often presented in a secondary window. It can present the data in a table making it easier for the user to find the value or values they want. With many datasets, the ability to sort the data, or narrow down the number of values presented is very useful.
Oracle ADF UIX provides elements which assist the developer in presenting an LOV to the
user. The elements open and manage the secondary window; manage the transfer of
data from the main window to the LOV window and back again; provide filtering
events; and provide a layout of appropriate fields in the secondary window. The
two main elements are the lovInput
element and the
listOfValues
element.
lovInput
element
First we'll look at an the lovInput
element. This element,
implements a simple text input field and a "flashlight" search icon. In its
simplest form, it takes a destination attribute. This attribute points to a UIX
page - containing a listOfValues
element - which will be used to
populate the secondary window. The UIX tag:
<lovInput id="myLOV"
name="myLOV"
columns ="10"
destination="LOVDlg.uix"
partialRenderMode="self"/>
will generate this:
Now, when a user enters text into the text field, a partial page
lovValidate
event will be generated (see the Partial Page Rendering and Client Actions in ADF UIX chapter for details on the
PPR architecture). The event will have the user's text in its
searchText
parameter. The event handler code can evaluate the
searchText and, if it matches one of the valid values for that field, accept
it. If it doesn't match a valid value, the developer will want to raise a
window from which the user can select one of the correct values. To do these
things, we need to extend our simple lovInput
a little bit:
<lovInput id="myLOV"
name="myLOV"
columns ="10"
destination="LOVDlg.uix"
text="${ui:defaulting(uix.data.fieldText,
uix.data.defaultText)}"
showWindow="${uix.eventResult.showWindow}"
partialRenderMode="self"/>
Now the text field has a default text but, more importantly, when the event
handler updates the provider for fieldText
, with the newly
validated value, it will automagically show up. So if your value data set is,
say, the fourteen 8000 meter mountain peaks, and the user types in the letter
'A', you'll know that the only matching peak is Annapurna, and you can update
the fieldData
provider with this full value. You already know,
from the Data Binding chapter, how to do this.
This auto-matching/auto-completion looks really cool! Your event handler would
be of the following form:
public static EventResult handleLovValidateEvent(
BajaContext context,
Page page,
PageEvent event
)
{
String searchText = event.getParameter("searchText");
// Implementation of matchPeak and MatchClass not shown, but
// matchPeak will validate the search text. MatchClass will keep
// the match data.
MatchClass matches = matchPeak(searchText);
if (matches.isValid())
{
// update the provider for the text attribute on the lovInput
fieldText.put(matches.getValidText());
}
return new EventResult(page);
}
Unfortunately, the user doesn't always know which peak they want. Sometimes
they only know the first letter of the peak name, they can't spell it
correctly, they mistype it, or they just want to test you. In these instances,
you can automatically bring up a new window to display a list of correct
values.
This is what the showWindow
attribute is all about. In most cases,
showWindow
should be cleared to false. When it is set to true on a
partial refresh, the lovInput
element will automatically send a
script to the client which will open a new window. Note that because
showWindow
doesn't need to persist across page renders, it can go
right onto the EventResult
. Now your event handler now looks like:
public static EventResult handleLovValidateEvent(
BajaContext context,
Page page,
PageEvent event
)
{
String searchText = event.getParameter("searchText");
// Implementation of matchPeak and MatchClass not shown, but
// matchPeak will validate the search text. MatchClass will keep
// the match data. This matchPeak matches on the peak name.
MatchClass matches = matchPeak(searchText);
if (matches.isValid())
{
// update the provider for the text attribute on the lovInput
fieldText.put(matches.getValidText());
}
else
{
// Save the MatchClass off to some persistent store so that searchText
// and possibly the matches are available for the LOV window.
}
EventResult result = new EventResult(page);
// only pop up the LOV window if there isn't an exact match
result.setProperty("showWindow", !matches.isValid());
return result;
}
Before the window comes up, you will receive an lovFilter
event
with the same text in the searchText
parameter so you can do the
real data retrieval at that point. It's important to handle this event because
in the non-partial-page-rendering cases you will not get an
lovValidate
event, and the user may choose to change their search
criteria from the LOV window (more on this later). The lovFilter
handler need not do anything special, it could look like this:
public static EventResult handleLovFilterEvent(
BajaContext context,
Page page,
PageEvent event)
{
// The source parameter tells you which lovInput field this came from
String source = (String) event.getParameter("source");
// Now do the search for the given text in the given category
// categories may be name, location, altitude etc. for this example
String cName = event.getParameter("choiceElementName");
String searchText = event.getParameter("searchText");
// Implementation of matchPeak and MatchClass not shown, but
// matchPeak will validate the input text. MatchClass will keep
// the match data. This matchPeak matches on the given category.
MatchClass matches = matchPeak(searchText, cName);
// and build the display data for the table on the LOV window
setTableDataProviderFromMatches(matches);
return new EventResult(page);
}
So, if the user were to type in a 'K', they might, now, expect to see a window something like this:
lovInput
's destination attribute points to
a page which will display the actual list of values - using a
listOfValues
element. Well, what you're seeing above is a page
with little more than a listOfValues
element and its table.
listOfValues
element
Now we're ready for the listOfValues
element. There's a lot to
this element, but it's mostly made up of other elements that you're already
familiar with. It boils down to this:
<listOfValues title="Available peak values"
id="lovHandler"
searchText="${uix.data.fieldData}">
<headerInstructions>
<styledText text="Choose a peak"
styleClass="OraInstructionText"/>
</headerInstructions>
<searchInstructions>
<styledText text="You can also change or refine your search.
Try searching on peaks using a search text of 'A',
'K', or 'M'. Try searching locations using an 'N'."
styleClass="OraInstructionText"/>
</searchInstructions>
<filterChoice>
<choice name="categoryChoice">
<!-- fill in the choices from the column headers -->
</choice>
</filterChoice>
<contents>
<!-- Here's the table definition -->
<!-- This must be a form submitted proxied table -->
<table name="lovTbl"
formSubmitted="true"
proxied="true"
... >
<!-- Populate with some data -->
</table>
</contents>
</listOfValues>
Yup, that's a lot, but let's take it a bit at a time. The main attributes are
easy, we've seem them all before. The id
attribute is simple and
familiar by now. The title
just provides a top level header for
the page - it'll appear right after the (translated) "Search and Select: " at
the top of the window. And you'll notice that the searchText
is
bound to the same data that the lovInput
's text
field
was. This makes sense because that's where the search text came from!
OK, next we have two types of instruction text named children.
<headerInstructions>
<styledText text="Choose a peak"
styleClass="OraInstructionText"/>
</headerInstructions>
<searchInstructions>
<styledText text="You can also change or refine your search.
Try searching on peaks using a search text of 'A',
'K', or 'M'. Try searching locations using an 'N'."
styleClass="OraInstructionText"/>
</searchInstructions>
The first, headerInstructions
, is used to give a general
description of what the user is supposed to do with this page. The second,
searchInstructions
, gives a detailed description of how the user
can refine their search (again, more on this soon).
Next, there's a filterChoice
named child
<filterChoice>
<choice name="categoryChoice">
<!-- fill in the choices from the column headers -->
</choice>
</filterChoice>
This child just takes a choice
element to show a pull-down list of
possible search categories. This is how the user can refine their search. If
the user is not happy with the values they are presented with, but they know
that the peak they're interested in is somewhere in Pakistan, they can switch
the category choice over to location (one of the table column headers), type
'Pa' into the search text field, and click 'Go'. You'll get an
lovFilter
event again - you can use the same handler to update the
table data.
And, finally, the sole indexed child is a table
element to present
the matches you got from filtering your base data using the users
searchText
.
<contents>
<!-- Here's the table definition -->
<!-- This must be a form submitted proxied table -->
<table name="lovTbl"
formSubmitted="true"
proxied="true"
... >
<!-- Populate with some data -->
</table>
</contents>
Of course you know all about the table
element from the
Creating Tables in ADF UIX chapter. One other thing, the contents element
usually takes a table
element, but it will really take any
arbitrary UINode
. Using this fact you can add extra data to the
submits you get with the table (or the search choice for that matter - they're
all in the same form) by setting the contents like this:
<contents>
<flowLayout>
<contents>
<table>
...
</table>
<formValue name="extraParam" value="${uix.current.secretParam}"/>
</contents>
</flowLayout>
</contents>
lovOpenWindowAction
Client Action
Sometimes you might want to do something other than transfer the selected value
back into a text input field. For these occasions, there is an
lovOpenWindowAction
Client Action (if you don't know about Client
Actions yet, see the Client
Actions section of the Partial Page Rendering chapter).
The lovOpenWindowAction
Client Action simply generates the code
necessary to launch an LOV window. It's pretty much exactly what is attached to
the search icon when you use an lovInput
element. Using this
element, you can launch an LOV from an arbitrary element. This could come in
handy if you want to allow the user to add rows to a table, but want to make
sure the rows are correct. Here's an example:
<button id="lovAddButton"
text="add rows"
shortDesc="Add more rows to the table">
<primaryClientAction>
<lovOpenWindowAction destination="LOVDlg.uix"
targets="peaksAddTable"/>
</primaryClientAction>
</button>
You could even have the list of values pre-filtered by adding an initial
searchText
to the action:
<button id="lovAddButton"
text="add more 'G' rows"
shortDesc="Add more 'G' rows to the table">
<primaryClientAction>
<lovOpenWindowAction destination="LOVDlg.uix"
searchText="G"
targets="peaksAddTable"/>
</primaryClientAction>
</button>
And that's it! Now you know the basic steps needed to build your own LOV. There are some more advanced features like Javascript callbacks, which we won't go into here. Please consult the Oracle Technology Network for code samples and demos.
Copyright © 2001, 2004, Oracle.
All rights reserved.