jQuery autocomplete
Asked Answered
W

2

10

I have an autocomplete text box that needs to respond to 2 events:

  • When the user is done typing something in the text box (I'm currently using focusout to assume when the user is done typing. So, if a user tabs out of a text box, it means the user is done typing.)
  • When the user selects an item in the autocomplete list of values (I'm using autocomplete's select event to determine that)

The Problem:

When the user selects an item in the autocomplete list of values, the chain of event is such that focusout is called first, then the select. When in focusout, I only have access to what the user typed, not what the user selected om the autocomplete list of values -- and that's what I actually need. How do I solve this problem?

Steps to Reproduce the Problem:

  1. In the text box, type the letter a
  2. Select ActionScript from the autocomplete list of values
  3. Observe console.debug messages:

    focusout event called
    a
    select event called
    ActionScript
    

Here's the code:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
        <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
        <title>Data Matching</title>
    </head>
    <body>
        <form>
            <input id="1" type="text"></input>
            <input id="2" type="submit"></input>
        </form>

        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>

        <script>
        $('#1').autocomplete(
        {
            select: function (event, ui)
            {
                "use strict";
                console.debug('select event called');
                console.debug(ui.item.value);
            },
            source: ["ActionScript", "AppleScript", "Asp", "BASIC", "C", "C++", "Clojure", "COBOL", "ColdFusion", "Erlang", "Fortran", "Groovy", "Haskell", "Java", "JavaScript", "Lisp", "Perl", "PHP", "Python", "Ruby", "Scala", "Scheme"],

            minLength: 1
        });

        $('#1').focusout(function ()
        {
            "use strict";
            console.debug('focusout event called');
            console.debug($(this).attr('value')); //  At this point, I need the value that was selected from autocomplete. I only get the value that the user typed, though
        });
        </script>
    </body>
</html>
Whatsoever answered 11/9, 2011 at 22:49 Comment(0)
A
8

This is precisely why jQueryUI introduced a special change event for autocomplete:

Triggered when the field is blurred, if the value has changed; ui.item refers to the selected item.

This event can do double-duty for both of your requirements:

$("#1").autocomplete({
    /* snip */
    change: function(event, ui) {
        if (ui.item) {
            console.log("ui.item.value: " + ui.item.value);
        } else {
            console.log("ui.item.value is null");
        }
        console.log("this.value: " + this.value);
    }
});
  • ui.item will not be defined when the user did not select a value from the list of autocomplete candidates.
  • On the other hand, this.value will always be correct.

Here's an example of this: http://jsfiddle.net/33GJb/

Amyloid answered 12/9, 2011 at 1:29 Comment(4)
This worked. I got rid of the focusout event handler. Thanks.Whatsoever
Am I right in saying that this doesn't quite meet the requirement "When the user selects an item in the autocomplete list of values" - since the change event is only triggered on blur (i.e. not immediately after an item is selected from suggestion list)?Whit
@JonoB: Not exactly but I believe (It's been awhile) that the OP's main issue was that he wanted to respond to the user either selecting an item or typing one in manually. You could combine change with select successfully as well.Amyloid
@AndrewWhitaker Ok thanks, that's what I thought - just wanted to check I haven't written more code than I have to.Whit
V
0

First off, just for educational purposes, it's important for anyone understand that these perticular events will always fire in this order. That being the case, I believe there are a few different ways you can solve the problem and here is what I came up with;

One: Build the application so multiple values selected by the user (type or selected) don't interfere. For instance, if the application is auto-correcting spelling, and someone typed "orphanag" on focusout the code that looked up the closest spelling would replace the value with "orphanage", than if someone actually selected "orphanages" it would then replace the value with the selected value. There most likely isn't an problem here, except the desire for over optimization.

Two: Have a flagged value either in Javascript or in the Html Element ("data-corrected=false") that exists. On FocusOut set a SetTimeout to wait a duration of time. Then if the users had selected a value, set your flagged value equal to true. When the duration is up, check the flagged value, if it is true don't do anything, else use the value in the input field for something.

Viola answered 11/9, 2011 at 23:30 Comment(4)
Erik, I was contemplating solutions like the ones you are suggesting. I'm hoping I won't have to go that route as it feels a bit hackish to me (but maybe it's not, maybe it's just the way things are and I have to deal with it). Any other ideas?Whatsoever
Not really, if you don't like one, then two is a signaling method, it's sorta like how threading works.Viola
Yeah ... #2 is probably a better fit for my problem.Whatsoever
If you aren't in a hurry, you might want to wait a day or two and see if there are other solutions.Viola

© 2022 - 2024 — McMap. All rights reserved.