Auto-Reduce Search Sample

For a while now I've been playing with techniques in ADF applications which will produce a user experience that is more webby (if I can use that term) and less business application like.  Some of this work can be seen if you look back on my postings on animation.

A recent challenge, in this vein, from one of the internal teams within Oracle, was to provide a search facility that would auto-reduce the results list in situe without the user having to press a button or link to trigger the search.

Now hopefully you're familiar with the component behaviour <af:autoSuggestBehavior> that will provide a drop down list below a test input that revises as you type. For example:

autosuggestBehavior in action

But that's not what I wanted here. In this case, I wanted the main search results to update as I typed - a feature you will find on certain popular search engines. As part of the process of putting this together, I found myself combining code and patterns from other prototypes that I've worked on and came to the conclusion that I could wrap all of this into a nice little demo application that actually shows several interesting techniques and patterns as well as the aforementioned auto-reduce.

Here's the screen, it's a simple search against ALL_OBJECTS in the database, and the features of it that I thought were interesting. 

Screen Shot of sample application in row view

  1. The screen uses a fixed width centered display area, a fairly popular layout pattern for a lot of sites, including this blog.
  2. The images displayed by each row use a technique called the ImageMap Pattern to derive the correct image to display. I'll be talking about two variants on this pattern, the more interesting one of which using image sprites as a way to reduce your network traffic.
  3. Typing in the search field will (after a configurable delay) cause the query to be re-executed and a revised list displayed.
  4. We have a dynamic record count which shows the records shown out of the total. 
  5. The list view here has a smart pagination bar which allows the user access to the start and end of the list without printing out every option in between.
  6. You can change how many records are displayed and hence the size of the pagination.
  7. Finally you can switch between row and icon views. This latter function is interesting because it's carried out client side to minimize the switch time.

The results of typing into the search screen would look something like this:

AutoReduce results

 As you type, not only will the list reduce, but of course the pagination bar etc. will be updated to reflect the current result set size.

The icon view mentioned in (7) looks like this:

Icon View

Over the next couple of weeks I'll be writing detailed articles on these various features, but if you can't wait to get started, you can download the sample from the ADF Samples project on Java.net: DRM004 - AutoReduce and Pagination screen

Comments:

Coincidentally I built the very same functionality last week (query as you type) and I can't help but noticing the 0.5 second delay you are using. I haven't run your code, but I bet it doesn't work without the delay, I ended up using document.getElementById() in my javascript to get the actual value of the field at the time of the keyUp and send that to the server in a parameter. Any other method was too fast and I ended up querying with a search parameter missing the last keystroke. Is that why you are using the delay?

I also noticed events being discarded during the typing, so when I type really fast I end up with 2 executions of the query: one for the very first character I type and one for the final search parameter. This is exactly what I want in my case but what if I want to process all keystrokes one day, would this even be possible?

Posted by guest on July 19, 2012 at 10:52 AM BST #

The point of the delay in the code (and you'll notice that there is some extra code to further ensure that multiple query events are not queued) is to reduce the load on the server.
The last thing you really want is a fresh query with every keystroke - that would hammer the server with query sets that would then be instantly replaced with the next one.
So the delay introduces a degree of both optimization from the server perspective, a reduction in the number of roundtrips from the browser to the server and a think time aspect to it all.
On the general matter of keystrokes I've had no problem with keystroke events being lost, however you have to be aware that due to the nature of AdfCustomEvent() you are unlikely to be able to pass every single discrete event from the browser to the server.
this is because the AdfCustomEvent() call actually places the event in a queue in the client. That queue will either be processed with the next scheduled roundtrip (e.g. a user presses a button) or, if no convenient piggyback happens the queue will be flushed to the server at a particular interval when the JavaScript thread is idle. This flush interval is, if I recall, 15ms, but I could be wrong.
Now the other aspect about the queue is that only one message of a particular event type will live on it at any one time. So should you submit two events of the same type within 15ms of each other, only the last one will be delivered to the server.
This may be why you think you're missing events.
All in all this is a good thing though. From a scalability point of view the last thing you want is hundreds of events over the AJAX channel within the space of a second. That would not be a good thing.

Posted by Duncan on July 19, 2012 at 03:15 PM BST #

Hi Duncan,

After consuming your demo, I changed the timeout handling slightly so that a CustomEvent was sent after a 500ms delay in typing. This is slightly different then your code, which creates the event every 500ms (regardless of whether the user is still typing). I haven't decided which implementation I like better, but this did lead to me discovering an interesting bug that might be related to the previous 'guest' comment.

The details are in Bug 14499596.

Basically, if an '_autoSuggest' event is delivered with any other non-immediate ADFCustomEvent (like the one created in 'queryCallback'), then the serverListener for that ADFCustomEvent will be bypassed (because the autoSuggestHandler renders the page and skips the other events in the request). My 500ms keyUp delay happened to almost be in perfect sync with the delivery of '_autoSuggest' events, which prevented my serverListener from getting these events. My workaround solution was to make my ADFCustomEvent immediate as well.

Just thought I should post this here in case any other users run into this issue.

Posted by Sam on August 15, 2012 at 09:33 PM BST #

Post a Comment:
Comments are closed for this entry.
About

Hawaii, Yes! Duncan has been around Oracle technology way too long but occasionally has interesting things to say. He works in the Development Tools Division at Oracle, but you guessed that right? In his spare time he contributes to the Hudson CI Server Project at Eclipse
Follow DuncanMills on Twitter

Note that comments on this blog are moderated so (1) There may be a delay before it gets published (2) I reserve the right to ignore silly questions and comment spam is not tolerated - it gets deleted so don't even bother, we all have better things to do with our lives.
However, don't be put off, I want to hear what you have to say!

Search

Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today