StackOverflowNewbie
StackOverflowNewbie

Reputation: 40633

jQuery autocomplete

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

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>

Upvotes: 10

Views: 7137

Answers (2)

Andrew Whitaker
Andrew Whitaker

Reputation: 126042

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/

Upvotes: 8

Erik Philips
Erik Philips

Reputation: 54618

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.

Upvotes: 0

Related Questions