Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FilteringSelect with a QueryReadStore: selection doesn't stick

I am using a dijit.form.FilteringSelect backed by a dojox.data.QueryReadStore in order to allow the user to select a region (think "auto-complete" mechanism). On each character entered by the user, the QueryReadStore sends a request to the server, awaiting a json list of matching regions (with associated IDs). By the time a short enough list is shown, the user picks the desired item. [Admittedly, querying on every keystroke is not the most efficient pattern, but it's good enough for now.]

Unexpected behaviour: in some rare but specific occasions, the choice made by the user "doesn't stick". For instance, if the user types "can", she is presented with the following choices in that order:

Atlantic Canada
Canada
English Canada
Lower Canada
Upper Canada
Western Canada

If she chooses "Canada" among these, the dijit closes the drop down selection, having correctly selected her choice. But by the time the user leaves the field, the selection switches to "Atlantic Canada"!

That bizarre phenomenon occurs systematically for a small number of specific regions. (At first, I thought that the common factor between those badly behaved regions was that their name contained accented characters or hyphens, but clearly not so with the Canadian example. So far, I fail to spot a regular pattern.)

I have not found any mention of a similar problem anywhere. I am quite willing to investigate, but, as I am new to dojo, I would really appreciate pointers before I resort to delving inside dojo's code: where should I first look? what are some likely problems that could cause that behaviour? can i rule out certain hypotheses? how should I best use the console (or Firebug) to get to the bottom of this? etc.

The problem occurs with both dojo 1.1.1 and dojo 1.2.3.

Here is the (programmatic) generation of the FilteringSelect:

new dijit.form.FilteringSelect({
   name = "region";
   autoComplete = false;
   hasDownArrow = false;
   labelAttr = "name";
   queryExpr = "${0}";
   store = new dojox.data.QueryReadStore({url:'/query/regions'});
}, myNode);

EDIT (2009/02/18): Additional details

Following damelin's answer, I wanted to understand what FilteringSelect saw of this situation. Suppose I connect logging functions to the FilteringSelect's events onChange and onBlur, I get the following play-by-play sequence:

  • I click in the field and type: can
  • drop-down list of 6 regions (listed above) appears
  • with the keyboard cursors, I move down the list to "Canada" (which is region with id 1)
  • I press Enter (thus selecting an item of the store). The drop-down list has by now disappeared and the text "Canada" appears in the field. At this point, the first event is fired, with the following logging:

    onChange event: region 1
    
  • I leave the field by pressing tab. Here, two events are fired one after the other, in the following order:

    onBlur event: region 1
    onChange event: region 246
    

(Region 246 is Atlantic Canada.) Now that's very interesting... By the time I leave the field (onBlur), Canada still is the selected value. The mysterious swap happens only after that...

like image 862
pierdeux Avatar asked Nov 24 '25 06:11

pierdeux


1 Answers

I think I finally found the explanation for such behavior. In a few words, it happens due to unfulfillment of contract, which FilteringSelect expects from QueryReadStore. And as QueryReadStore totally relies on response from server module, which generates json, it could not fulfil contract due to unexpected response from server.

As I figured out, at the end of user input FilteringSelect expects Store (QueryReadStore in this case) to only return items that exactly match entered or selected string. FilteringSelect consider that input is ended when enter key pressed or when user leaves field. Before this two events, text, which is entered or selected is just text. No item is actually selected at the moment.

In other words, at the end of input, FilteringSelect expects Store to return zero items if nothing should be selected, or one item, that should be selected. So, then you provide list of regions, FilteringSelect just can't determine which one to choose, and stops at first of them.

As you mentioned, QueryReadStore sends request at every keystroke. At this case (before input ended) FilteringSelect expects Store to return items that match pattern. By default pattern is "enteredString*" where asteriks is any sequence.

To distinguish between two cases, QueryReadStore slighlty vary requests:

  • sample request on every keystroke: /query/regions?name=enteredString*&start=0&count=5
  • sample request on end of input: /query/regions?name=enteredString&start=0

As you see, in second request there is no asteriks at the end of "enteredString". This variations could help to build correct response at server side.

I hope I have explained it well. If not, you are welcome to ask.

like image 83
damelin Avatar answered Nov 28 '25 02:11

damelin