views:

6243

answers:

3

We are using the autocomplete jquery plugin written by Jörn Zaefferer, and are trying to verify a valid option is entered.

The plugin has result() event which fires when a selection is made. This is OK, but I need to check the value in the textbox when a user clicks out too. So we have tried a .change() and .blur() events, but they both pose an issue: when you click on an entry in the results div (the 'suggest' list) the .change() and .blur() events fire, and this is before the plugin has written a value to the textbox, so there is nothing to verify at this point.

Could someone help me configure events so whenever someone clicks away, but not in the results box I can check for a valid value in the box. If this is the wrong approach please inform me of the correct one. We originally went with this plugin because of its 'mustMatch' option. This option doesn't seem to work in all cases. Many times a valid entry will be written into the textbox and than cleared by the plugin as invalid, I have not been able to determin why.

Basic Code example:

<html>
<head>
<title>Choose Favorite</title>
<script language="JavaScript" src="jquery-1.3.2.min.js" ></script>
<script language="JavaScript" src="jquery.autocomplete.min.js" ></script>
<script>
    $(".suggest").autocomplete("fetchNames.asp", {
        matchContains:false,
        minChars:1, 
        autoFill:false,
        mustMatch:false,
        cacheLength:20,
        max:20
    });

    $(".suggest").result(function(event, data, formatted) {
        var u = this;
        // Check value here

    });

    /* OR */

    $(".suggest").change(function(me) {
        //check value here
    });

</script>
</head>
<body>
    <label for="tbxName">Select name (I show 10):</label><br />
    <INPUT type="text" id="tbxName" name="tbxName" class="suggest"><br />
</body>
</html>
+4  A: 

UPDATE: This should work. I am loading the list of names into an Array called ListOfNames, this is used in the onBlur() event to verify the name entered against the data. You may need to do some tweaks, but I think it should do what you're looking for.

var listOfNames = [];
$(document).ready(function(){
   $.get("fetchNames.asp", function(data){
     listOfNames = data.split("\r\n");    
   });
   $(".suggest").autocomplete("fetchNames.asp", {
        matchContains:false,
        minChars:1, 
        autoFill:false,
        mustMatch:false,
        cacheLength:20,
        max:20
    });
    $("#tbxName").blur(function(){
        if(!listOfNames.containsCaseInsensitive(this.value)){
          alert("Invalid name entered");
        }
    });        
});

Array.prototype.containsCaseInsensitive = function(obj) {
  var i = this.length;
  while (i--) {
 if (this[i].toUpperCase() === obj.toUpperCase()) {
   return true;
 }
  }
  return false;
}
Jose Basilio
Thank you for your response. This isn't quite doing it. If I select a value, it fills in properly, once I click away it errors, invalid. If I enter a couple of characters then click away, no error is raised, though I do need to ad my db check.
Brettski
What is fired first, .blur() or .change()?
Brettski
Thank you again for your response. Possible names which may come back from fetchnames.asp is 32,000, not sure if I want to store all that data in an array. I like the approach though
Brettski
In that case, the correct approach would be to have your fetchNames.asp accept a querystring parameter equal to the name to verify. Ex: searchNames.asp?name=John .... return the name if found, otherwise a blank string. This can be added to the onBlur() event. Does that make sense?
Jose Basilio
this.value of the .blur() event will only contain the items I have typed into the box, not the item I am trying to select. So it will never match. I type into the textbox and receive my suggestions, as soon as I click to select one, the .blur() fires, but the click event to write the value into the textbox hasn't happened yet. Does that make sense?
Brettski
@Brettski - I think this may not even be possible with this approach. Here's a similar post: http://stackoverflow.com/questions/328430/jquery-autocomplete-determining-if-entered-text-is-not-a-match
Jose Basilio
However, If the form has other input fields, you may fire the validation when the user enters another input box. While not ideal, it may be the only way.
Jose Basilio
+5  A: 

I think rather than writing your own function to verify if the data matches, you can just call search(). If result() is called with a null data parameter, then you know that auto-complete wasn't used and by calling search() on blur, you're guaranteed to get result() called at least once.

I've posted this code for a similar question, it may help here as well.

autocompleteField.result(function(event, data, formatted) {
    if (data) {
        //auto-complete matched
        //NB: this might get called twice, but that's okay
    }
    else {
        //must have been triggered by search() below
        //there was no match
    }
});

autocompleteField.blur(function(){
    autocompleteField.search(); //trigger result() on blur, even if autocomplete wasn't used
});
npdoty
Good answer! Do you know maybe how to prevent the result event firing twice? This is the problem, if this event performs some complex logic, like validate the input on server via ajax request.
Kamarey
If you're doing a lot of processing in `.result()`, you can try to maintain a flag to see if your `if (data)` branch has already been called. I can warn you that this will be non-trivial though: you can easily set the flag at the end of `if (data)`, but you'll need to clear it in cases where the user edits the auto-completed suggestion. I would try using `.change()` for that. Good luck!
npdoty
A: 

I use a global data structure to keep track of the values that were found

var ac_sent = {};

the .result() event handler is called before the .change() event handler, so in .result( event, data, formatted ) I add the data to the structure:

ac_sent[ data ] = true;

then in the .change( event ) event handler I check to see if there is an item at ac_sent[ data ], and if there isn't any, I know that the word was not found:

$( "#textbox" ).change( function( event ) {

  var data = event.target.value;

  if ( !ac_sent[ data ] ) {
    // result was not found in autocomplete, do something...
    ac_sent[ data ] = true;  // remember that we processed it
  }

  return false;
});
Jay
The result() event triggering before the change() event is not 100% accurate. It happens in that order if the Enter key is used to select an item from the list. However, if the mouse is used then event order is reversed -- change() happens first, followed by result().
Jason