Advanced usage of the Typeahead control in Rational Application Developer V7.0

Adding server-side dynamic filtering, styling, using the event API and much more!

There is an ever-growing need for a rich user experience when it comes to Internet applications. An approach to Web application development that has been very successful and popular recently is to design Web applications using Ajax-style patterns. One of the Ajax features available in IBM® Rational® Application Developer is the Typeahead component. This article demonstrates the versatility of this component in a number of areas: Server-side dynamic result filtering, CSS customization, and JavaScript™ event handling using the JavaScript API. It takes you, the Web developer, beyond the most straightforward use cases, and into more advanced Typeahead usage.

Adam Bermingham, Software Engineer, IBM

Adam Bermingham photoAdam Bermingham has been a Software Engineer working in the IBM Dublin Software Lab since October 2004. He graduated from Trinity College, Dublin with a B.A. (Mod) in Computer Science, and he is a Sun-certified Java programmer. He has been working developing the runtime for IBM's Enhanced JavaServer Faces Components and, recently, on IBM LanguageWare.



06 February 2007

Also available in Chinese Russian

Introduction

The Enhanced JavaServer Faces™ (JSF™) Components in IBM®Rational® Application Developer, together with the Standard JSF Components, offer a broad range of high-level functionality that can be used to rapidly develop a rich and robust Web application. Not only is the library extensive, each component in itself is very versatile, reusable, and, perhaps most importantly, customizable. This flexibility refers to both the component structure on the client-side, as well as the business logic on the server. A fine example of this is the Enhanced Faces Typeahead component. This article will cover a number of advanced techniques that demonstrate how easy it is to customize and get the most out of the Typeahead component. The main areas covered will be:

  • Creating a server-side Dynamic Filter
  • Changing the look and feel using CSS and the tag attributes
  • Using the Typeahead events and the JavaScript™ API

This article assumes that you have some familiarity with the tooling for the JSF components in Rational Application Developer. For a step-by-step guide to creating your first Typeahead component, please refer to the introductory article in the Resources section.

Implementing a server-side Dynamic Filter

The most straightforward use case for a Typeahead component consists of a simple dictionary lookup. For example, when you type a string the drop down is populated with a list of popular search terms, all of which begin with the String typed by the user (as shown in Figure 1).

Figure 1. A simple Typeahead
typeahead with the word zygobranch

In the background, what is happening is:

  1. On the Client side, the script (written in the JavaScript programming language) registers that a string has been entered in the input field (a keydown event has occurred).
  2. The Enhanced Faces JavaScript Library backchannel object submits the search term to the server in the background. The backchannel encapsulates all of the functionality and logic required either to send an XMLHttpRequest to the server, or to submit the information via a hidden iFrame, depending on the circumstance.
  3. On the server, a response is constructed in the form of XML. You should be able to see the response (and the request) in any good JavaScript browser console with the ability to track XMLHttpRequest traffic. A typical XML response (two XML islands) looks like the code in Listing 1:
    Listing 1. Typeahead XML Server Response with 2 results
    <?xml version='1.0' encoding='ISO-8859-1'?>
    <taresponse>
    	<suggestlist>
    		<suggestion>bd0772-Ja</suggestion>
    		<suggestion>ede651-Ja</suggestion>
    	</suggestlist>
    </taresponse>
    <url>/test2/myPage.faces?$$ajaxid=form1:typeahead1&$$ajaxmode=axpartial</url>
  4. In the script, there is a Callback function registered with the XMLHttpRequest. This is called passing in the response as a parameter. The Typeahead script then creates a suggestion list in the Document Object Model (DOM) by inserting a system of HTML tables and divs.

From your perspective as the user, the population of the drop-down is seamless and, most importantly, doesn't require a reload of the page. Once the list is populated, you can use your mouse or your keyboard to select an option from the list. This completes the input in the input field, just as with any standard dropdown control.

Often, you need to introduce more complexity into the logic that manages the back-end search. Following is a simple example that illustrates how a filter can be applied in the search process.

Bean structure

In this example, the structure is as shown in Figure 2.

Figure 2. Structure of the sample bean
filter and search logic, and data structure

The bean package (typeaheadFilter.zip, available in the Downloads section) structure is essentially divided in two. The data structure beans are on one side:

  • Company
  • Customer
  • Order

As you would expect, the pattern is a familiar one: a company with many customers, who in turn have many orders.

On the other side is the search logic. The Map that binds to the Typeahead is the SimpleSearch bean, which is referenced by the SampleFilter bean. The filter bean contains state information about the current filter. The search bean can access the state of the filter bean in order to determine which results are returned in the suggestion list. Both sides are referenced by a Root bean.

The Root bean creates a Company object. The Company object in turn creates four objects of type Customer:

  • Wender's Washers
  • Jackson's Juggernauts
  • Pierre's Plumbing
  • William's Web Development

Each Customer generates 30 objects of type Order. For each Order, an ID String is created that consists of a Hexadecimal value (up to 0xf00000), followed by a hyphen, followed by the first two letters of the customer's name (for instance, ede651-Ja or bd0772-Ja). Although these numbers are not absolutely guaranteed unique, they are sufficient for the purposes demonstrated here. These are the codes that will be searched by the Typeahead.

Writing search logic

A bean that extends the type java.util.AbstractMap (in this example, shown in Listing 2, the SimpleSearch bean) encapsulates the search logic for the Typeahead. The Typeahead calls the get method of the Map bean. The get method should return one of the following:

  • an ArrayList containing Strings
  • a single String (this can be returned in the case of a single result)
  • null

Click to see code listing

Listing 2. Search logic in SimpleSearch bean

	public Object get(Object key) {
		Customer[] customers = filter.root.company.getCustomers();
		ArrayList matches = new ArrayList();
		int len=0;
		String s = (String)key;
		System.out.println("in search, key: " + key);
		for(int i=0; i<customers.length; i++)
		{
			// the following line filters out customers which don't match our filter
			if (!customers[i].CustomerName.equalsIgnoreCase(filter.getFilter())) continue;
			System.out.println("using customer: " + customers[i].CustomerName);
			// if it gets to here we have a 
			Order[] orders = customers[i].getOrders();
			for (int j=0; j<orders.length; j++){
				String record = (String) orders[j].getOrderID();
				if (record.length() > s.length()) {
					String subrecord = record.substring(0,s.length());
					if (subrecord.equalsIgnoreCase(s)==true) {
						System.out.println("adding record to matches: " + record);
						matches.add(len++,record);
					}
				}
			}
		}
		return matches;
	}

In Listing 2, note the two bold lines, which change what would otherwise be a search of all the orders into a search whereby the only orders searched are those whose owner Customer Name matches the filter String. So, if the filter is set to "Pierre's Plumbing", only the orders associated with that customer will be searched. This is a very simple scenario, but you could apply the same technique to, for example:

  • Getting all customer orders within a range of dates
  • Filtering based on some environmental variable

Creating a simple demonstration application in Rational Application Developer

With little difficulty, you can create an application in Rational Application Developer that shows the above filtering in action. To create a new application and import the beans, perform the following steps.

  1. Create a new Dynamic Web Project with Faces support, targeted at a server in your development environment, as shown in Figure 3. Servers supported by the Typeahead are IBM® WebSphere® Application Server (V6.x or later), IBM® WebSphere® Portal Server (V5.1 or later), and Apache Tomcat V5.5.
    Figure 3. New Dynamic Web Project Dialog
    enter project name, contents, and target runtime
  2. Import the beans into the project. To do this, right-click the project and select Import > Archive File, and then navigate to the directory where you saved the typeaheadFilter.zip file. Make sure that you select to import the files into the source (default is "src") folder in your project, as shown in Figure 4.
    Figure 4. Importing the JavaBean package
    import from archive file to folder
    Next, you need to create a page with JSP™ (JavaServer Pages™) technology, and then create page data.
  3. Create a new Web page in the WebContent folder of your project by right-clicking the folder and selecting New > Web Page, as shown in Figure 5.
    Figure 5. Create a new JSP
    do so in the Project Explorer
    Enter a name for the page and select Finish.
  4. In the Page Data View, create a new Faces Managed Bean. In the Class section in the Add JavaBean dialog, enter com.ibm.devworks.typeaheadfilter.Root, as shown in Figure 6. You can do this quickly using the helper button on the right. Make sure to set the Scope to session.
    Figure 6. Adding a Faces Managed Bean, "Root"
    make the bean reusable
    Now, you need to add some components for data input and output.
  5. Drag the filter field of the filter class from the Page Data View onto the Page, as shown in Figure 7. Select Inputting data from the dialog.
    Figure 7. Adding controls for the Filter
    green arrow shows where to drag
  6. Drag an input field from the Enhanced Faces Components drawer (on the right) onto the page. (If the drawer isn't there, you may need to Unhide it from the Palette Customization dialog.) This input field will be your Typeahead control. This example (Figure 8) has a table and a small piece of text on the page to identify the field and lay it out neatly.
  7. Although this isn't necessary, you can drag the Company node from the Page Data view onto the page in order to display the contents of the of the Data in a nested DataTable. This can help visualize the data set at runtime while in development.
    Figure 8. JSP in Design view with controls
    index.jsp tab
    At this stage you are ready to Typeahead-enable your input field.
  8. On the Behavior tab (in the Properties view) for the input field, enable Typeahead functionality by selecting the Enable typeahead option checkbox. Note that in the Source view you can see that a hx:inputHelperTypeahead tag has been added as a child to the h:inputText tag.
  9. On the Design tab, drag the search object from the Page Data view onto the Typeahead helper button next to the input field, as shown in Figure 9. (Note: If you are prompted to provide a containing type for the Map, java.lang.Object is fine).
    Figure 9. Drag the search object to bind the Typeahead
    again shown with a green arrow

The application is now ready to run on the server, and should look like the page shown in Figure 9 when running. By entering different customer names and clicking Submit, you can see (Figure 10) that the result set for the Typeahead changes according to which Customer the filter is currently set to. You can put together this application in a matter of minutes.

If you invest a little more time, you can develop complex filter and typeahead systems with this technique. A Logical next step for this application would be to typeahead-enable the Filter (Customer input) field also. This would be useful in cases where there are a large number of customers.

Figure 10. Running on server (note that only Wender's Washer's Orders are returned)
typeahead results filtered by customer

This example uses JavaBeans technology because it works well as a simple illustration. However, you can use any backend as a datastore. This can be quite powerful. You could, for example, tailor SQL queries for the task at hand, and use the JDBC (Java™ Database Connectivity API) mediator to access a database.


Event handling

The events for the Typeahead are inProgress, oncomplete, onstart, and onerror. The event handling is specified in the Quick Edit view for the Typeahead. You can associate each of this with a JavaScript function. For the moment, concentrate on adding a JavaScript event handler for the oncomplete event.

inProgress and onerror

The inProgress and onerror events are not yet available in the Rational Application Developer v7.0 release, but should be available in an update soon. Watch this space!

A simple handler

You need to associate a function with the tag. You can do this in the Quick Edit view, as shown in the following steps.

  1. Select oncomplete on the left side of the view.
  2. On the right side, enter an alert (You are in the oncomplete event handler).

Code along the lines of that in Listing 4 should generate in the Source view for the page.

Listing 4. A simple event handler
<script type="text/javascript">
	function func_1(thisObj, thisEvent) {
		//use 'thisObj' to refer directly to this component instead of keyword 'this'
		//use 'thisEvent' to refer to the event generated instead of keyword 'event'
		alert("You are in the oncomplete event handler");
	}
</script>
.
.
.
<h:inputText id="text1" styleClass="inputText">
	<hx:inputHelperTypeahead id="typeahead1" styleClass="inputText_Typeahead" 
		value="#{myRoot.filter.search}" oncomplete="return func_1(this, event);">
	</hx:inputHelperTypeahead>
</h:inputText>

You can quickly verify that this works by running the page on the server. When the client receives the suggestion list, a pop-up message box displays. The thisObj mentioned in the generated comment refers to the DOM input field with which the Typeahead is associated. This can be useful for getting its dimensions, contents, id, and so on.

The Typeahead Behavior object

What can be more useful, however, is retrieving the JavaScript Typeahead Behavior object. A Behavior is a concept in the Extended Faces JavaScript library, in which a type of functionality can be associated with a DOM object, an event, and a type of Behavior. In this case, the DOM object is the input field, the event is onkeydown, and the type of behavior is typeahead, resulting in code similar to that shown in Listing 5.

Listing 5. Retrieving the Typeahead behavior object
var myTypeahead = hX_5.getBehaviorById(thisObj.id,"typeahead","onkeydown");

Having access to this object allows you to retrieve a suggestion String by index. Listing 6 shows a sample handler that iterates through the suggestions, appends them to a String, and then alerts them to the user (Figure 11).

Listing 6. A handler that gets and displays the list of suggestions from the Typeahead
<script type="text/javascript">
	function func_1(thisObj, thisEvent) {
		var myTypeahead = hX_5.getBehaviorById(thisObj.id,"typeahead","onkeydown");
		var i, s = "The suggestions are: \n";
		for(i=0; i<myTypeahead.suggestionCells.length; i++)
		{
			s += (i+1) + ". " + myTypeahead.getSuggestion(i) + "\n";
		}
		alert(s);
	}
</script>
Figure 11. Accessing the suggestions in an Event
list of suggestions

What the user typed

Another thing you may wish to do is to get the text in the input field. After the suggestion list is returned, the first result is inserted into the input field. If this result is not equal to the string typed so far, the text of the input field changes to the first suggestion, highlighting the portion of the suggestion that was added to the input field text during the autocomplete process. The Typeahead object stores the length of the string that the user entered in a variable called typedLength. You can therefore easily get the user input string from the Typeahead using the code shown in Listing 7.

Listing 7. Getting the user-typed string from the Typeahead Behavior
var myTypeahead = hX_5.getBehaviorById(thisObj.id,"typeahead","onkeydown");
var typedSoFar = thisObj.value.substring(0,myTypeahead.typedLength);

Changing the look and feel

One of the great things about the Enhanced JSF Components packaged with Rational Application Developer is their high-level of customizability. In this section, you will learn how to take advantage of this customizability through CSS and tag attributes using the Rational Application Developer tooling. This article will look at three different contexts for the Typeahead, and examine how you can change its look and feel appropriate to each context. Included are snippets of the JSP code and the corresponding CSS styles (where applicable).

Non-intrusive dropdown

Often, dropdowns in the GUI (graphical user interface) for a Web application can appear intrusive. This is particularly true in the case where you are unlikely to need to use it. In many of these scenarios, there are a minority of use cases where Typeahead assistance could be very useful. For example, consider the case where you are typing in a given name. Usually there would be no trouble, since given names are common and typically less than eight characters. In the case where you are unsure of the spelling, you could greatly benefit from Typeahead support. Then you can just type the first few letters of the name and choose from a list. Another similar scenario is when a Web developer does not want to obscure information on the page, particularly if the user input relies on being able to view the whole page content.

One way to make your Typeahead less intrusive is to reduce the size of the dropdown. You can achieve this using two approaches. The first is to reduce the number of lines that appear in the dropdown. This can easily be done on the Properties tab for the hx:inputHelperTypeahead by entering a number in the Height of Suggestion Area field. You will note that there is also a Maximum number of suggestions displayed field (Figure 12). This should be used only to limit the number of results that are sent back from the server.

The code that transmits the XML result list (Listing 8) will only include up to n results, where n is the maximum to be returned. If you set the height of the suggestion list to a number less than the number that is returned, that will automatically turn on vertical scrolling in the dropdown. In this way, there is no need to compromise the size of the result set in minimizing the intrusion on screen.

Figure 12. Restricting Height of Dropdown
setting Typeahead properties
Listing 8. The result size attributes
<h:inputText id="text1" styleClass="inputText">
	<hx:inputHelperTypeahead id="typeahead1" styleClass="inputText_Typeahead" 
		value="#{myRoot.filter.search}" oncomplete="return func_1(this, event);" 
		size="2" maxSuggestions="100"></hx:inputHelperTypeahead>
</h:inputText>

A second option is to omit the Typeahead dropdown completely by activating autocomplete mode. When autocomplete mode is active, no dropdown displays on the page, but your input autocompletes to the first result in the result set returned from the server. In this way, the Typeahead control does not use any extra screen real estate. This can be useful in cases where the result set is small, and you will infrequently wish to choose between more than one option.

For example, consider a case where you are typing in a name from your list of contacts. Typically, typing in a first name and the first couple of letters of the surname can yield a single result. The functionality of selecting from a result set is not compromised, however, as you can still cycle through the result set using the arrow keys on the keyboard.

A third way to reduce intrusion is to introduce transparency to the dropdown. If the dropdown has a reduced opacity, your attention will not be as diverted from the input field during the input process. If the dropdown is sufficiently transparent, you should still be able to view information on the page and, if necessary, draw on it to enter details into the input field. Figure 13 shows an example of this.

Figure 13. A transparency-enabled Typeahead
you can see through the drop-down list

Listing 9 shows the CSS for three of the Typeahead classes used to produce the transparency effect on the dropdown area. The attributes that pertain to transparency are in bold.

Listing 9. Transparency in CSS
.inputText_TypeAhead {	
background-color: #ccddff;
	border-width: 1px;	
	border-style: solid;	
	border-color: ThreeDDarkShadow;	
	width:300px;	
	-moz-opacity: .7;	
	opacity: .7
	}

.inputText_TypeAhead-List {
	background-color: transparent;
	text-align: left;
	vertical-align: middle;
	height: auto;
	font-family: sans-serif;
	font-weight: 400;
	font-size: 10pt;
	border-collapse: collapse
}

.inputText_TypeAhead-Item {
	background-color: transparent;
	color: WindowText;
	padding-left: 1pt;
	padding-right: 1pt
}

Displaying lengthy suggestions with a long suggestion list

It is often inconvenient if you have to type in long strings in an input field (for example, if you are typing a long chemical compound name or an address). The Typeahead can help you with this by offering a list of suggestions after only a fraction of the full String has been typed. This could potentially be very efficient if a dataset with an average string length of 150 characters can typically be differentiated using only the first <10 characters.

In order to achieve the intended effect, it is necessary to alter the style of the Typeahead somewhat. Although the Typeahead can handle wrapping text, this is undesirable, particularly when a suggestion wraps more than once. Instead, you can increase the width of the suggestion area through CSS. By default, the width of the suggestion area is set to that of the input field. Even though you may want to make your input field longer for longer Strings, having an exceedingly large input field does not make for neat or compact design. The way to stop the dropdown from snapping to the width of the input field is to clear the Match width of the suggestion area with the input field checkbox in the hx:inputHelperTypeahead Properties view. This sets matchWidth=false on the Typeahead tag.

Figure 14. Matchwidth checkbox
changing the width in Properties

Next, you need to specify the width in the CSS, resulting in a GUI similar to that in Figure 15. You can use any metric that is acceptable in CSS for specifying the width. For this example, yset the width to 400px. The CSS width attribute in the base CSS class is the only change required, as shown in Listing 10.

Listing 10. Extended width in CSS
.inputText_TypeAhead {	
background-color: #ccddff;
	border-width: 1px;	
	border-style: solid;	
	border-color: ThreeDDarkShadow;	
	width: 400px;	
	-moz-opacity: .7;	
	opacity: .7
	}
}
Figure 15. A wide dropdown
a dropdown wider than the field

Now you can freely control the width of the Typeahead, either absolutely (by specifying exact widths) or relative to its containing element (by specifying a percentage).

Unfamiliar strings

It is troublesome to try to enter Strings that you do not know offhand, or that would be difficult to type, like long alphanumeric Strings. These types of Strings could, for example, be a part number or an ID number. In these cases, it is best to fire the request for the suggestion list early in the input process. There are two fields in the Properties view that control when the Ajax request for the suggestion list is fired:

  • One fires the delay only after you have entered at least a specified number of characters
  • One controls the amount of time that has elapsed since the last user keydown event

The defaults for these attributes, startCharacters and startDelay (shown in Figure 16), are one character and 500 milliseconds respectively. In the case of unfamiliar Strings, it might be beneficial to reduce the time delay to say 100ms.

Figure 16. The delay attributes
set the delay attributes

Caution when reducing delay time

Reducing the delay time to 0 or near zero can be unpredictable, because there is a race between the keydown event and the Ajax request to the server. It is possible that the request to the server may be fired using the previous value of the input field.

However, as with all Ajax, this can significantly increase the traffic on the server. It is recommended that you combine these two attributes effectively to optimize the tradeoff between the performance and usability of your Typeahead. For this reason, conversely, when you are very familiar with the String you are typing, it makes sense to increase these attributes.


Download

DescriptionNameSize
Sample beans for Typeahead filtering scenariotypeaheadFilter.zip4 KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Rational software on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Rational, WebSphere
ArticleID=193342
ArticleTitle=Advanced usage of the Typeahead control in Rational Application Developer V7.0
publish-date=02062007