views:

327

answers:

3

Yeah, this is indeed my third or fourth question about jQuery UI Autocomplete. My latest annoyance is that clicking the 'submit' button in a form does not seem to count as a 'change' for jQuery. When my input box changes, jQuery runs some javascript to force a match against a list of acceptable inputs and their values:

jQuery("#Resource").autocomplete({
   source: function( request, response ) {
    var matcher = new RegExp(jQuery.trim(request.term).replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i" );
    var matches = jQuery.grep(resources, function(value) {
     return matcher.test( value.label || value.value || value );
    });
    response(matches.length ? matches : [{ label: "No Result Found", value: "" }]);
   },
   focus: function(event, ui) {
    jQuery('#Resource').val(ui.item.label);
    return false;
   },          
   select: function(event, ui) {
    jQuery('#Resource').val(ui.item.label);
    jQuery('#EmployeeNumber').val(ui.item.value);
    return false;
   },
   change: function(event,ui) {
    for(var i in resources){
     jQuery('#EmployeeNumber').val("");
     if(resources[i].label.toLowerCase()==jQuery('#Resource').val().toLowerCase()) {
      jQuery('#EmployeeNumber').val(resources[i].value);
      break;
     }
    }
   }

  });

If the EmployeeNumber (hidden) input already has a value, entering an invalid name and then tabbing or clicking off of the input box clears this value, however if you instead immediately hit the form Submit button, it does not seem to count as a 'change' and the POST data includes the previous EmployeeNumber value - making what should be an incorrect input 'sort of' correct!

Is there either some way I can make the jQuery recognise that clicking 'Submit' is also a change, or else some way I can get the Submit button to notify the jQuery that the Resource input has been clicked off of?

UPDATE:

In the end, I got around this by using what I consider a rather hacky method - I abandoned the 'change' event of the auto-complete box and did that matching myself manually when the user clicks submit. The way it work now is that if the user chooses a name by clicking on the auto-complete drop-down menu, the EmployeeNumber value will be filled in by the auto-complete jQuery code. If the user just types a name and hits submit, then the matching is instead done by the forceCheck() function. Of course this function will automatically match against the first name regardless of whether or not there is a second identical name, but unfortunately in what seems like the weirdest quirk I've ever seen, any code after the end of that for loop does not get executed, even if there is no 'return' statement in the loop. After the loop finishes the submit request just continues... it's so very odd.

<fieldset class="submit">
    <input id="Submit" name="Submit" type="Submit" class="Submit" value ="Submit" onclick="document.getElementById('Resource').value = jQuery.trim(document.getElementById('Resource').value);forceCheck();"/>
</fieldset>

...


<script type="text/javascript">

    ...

    // Force a resource name check when the user hits the submit button. Necessary because if user changes Resoruce
    // input then hits submit directly (no click or tab off), the jQuery 'change' event (see below) isn't fired
    // until *after* the submit button has begun processing, which is too late.
    function forceCheck() {
        for(var i in resources) {
            document.getElementById("EmployeeNumber").value = "";
            if(resources[i].label.toUpperCase() == document.getElementById("Resource").value.toUpperCase()) {
                document.getElementById("EmployeeNumber").value = resources[i].value;
                return;
            }
        }
    }

    jQuery(function(){
        jQuery("#Resource").autocomplete({
            source: function( request, response ) {
                var matcher = new RegExp(jQuery.trim(request.term).replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i" );
                var matches = jQuery.grep(resources, function(value) {
                    return matcher.test( value.label || value.value || value );
                });
                response(matches.length ? matches : [{ label: "No Result Found", value: "" }]);
            },
            focus: function(event, ui) {
                jQuery('#Resource').val(ui.item.label);
                return false;
            },          
            select: function(event, ui) {
                jQuery('#Resource').val(ui.item.label);
                jQuery('#EmployeeNumber').val(ui.item.value);
                return false;
            },  
        });
    }); 
</script>

If anyone knows a better way than this, I would very much appreciate your answer - or if you know why the remainder of my forceCheck function might not run... Otherwise, I will post this post as an answer to my own question tomorrow, and accept it when I can (2 days afterwards, I believe).

Final Update:

Well, it's been more than 24 hours (quite a lot more), so I've posted my solution up as an "answer". I'll leave it a few more days then accept it if there's still no other answer.

A: 

Can you add

submit: function(event,ui) {
// same thing as your change:
}
Crayon Violent
jQuery UI autocomplete doesn't have a `submit` event... See [here](http://docs.jquery.com/UI/Autocomplete#events).
Stephen
A: 

In the end, I got around this by using what I consider a rather hacky method - I abandoned the 'change' event of the auto-complete box and did that matching myself manually when the user clicks submit. The way it work now is that if the user chooses a name by clicking on the auto-complete drop-down menu, the EmployeeNumber value will be filled in by the auto-complete jQuery code. If the user just types a name and hits submit, then the matching is instead done by the forceCheck() function. Of course this function will automatically match against the first name regardless of whether or not there is a second identical name, but unfortunately in what seems like the weirdest quirk I've ever seen, any code after the end of that for loop does not get executed, even if there is no 'return' statement in the loop. After the loop finishes the submit request just continues... it's so very odd.

<fieldset class="submit">
    <input id="Submit" name="Submit" type="Submit" class="Submit" value ="Submit" onclick="document.getElementById('Resource').value = jQuery.trim(document.getElementById('Resource').value);forceCheck();"/>
</fieldset>

...


<script type="text/javascript">

    ...

    // Force a resource name check when the user hits the submit button. Necessary because if user changes Resoruce
    // input then hits submit directly (no click or tab off), the jQuery 'change' event (see below) isn't fired
    // until *after* the submit button has begun processing, which is too late.
    function forceCheck() {
        for(var i in resources) {
            document.getElementById("EmployeeNumber").value = "";
            if(resources[i].label.toUpperCase() == document.getElementById("Resource").value.toUpperCase()) {
                document.getElementById("EmployeeNumber").value = resources[i].value;
                return;
            }
        }
    }

    jQuery(function(){
        jQuery("#Resource").autocomplete({
            source: function( request, response ) {
                var matcher = new RegExp(jQuery.trim(request.term).replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), "i" );
                var matches = jQuery.grep(resources, function(value) {
                    return matcher.test( value.label || value.value || value );
                });
                response(matches.length ? matches : [{ label: "No Result Found", value: "" }]);
            },
            focus: function(event, ui) {
                jQuery('#Resource').val(ui.item.label);
                return false;
            },          
            select: function(event, ui) {
                jQuery('#Resource').val(ui.item.label);
                jQuery('#EmployeeNumber').val(ui.item.value);
                return false;
            },  
        });
    }); 
</script>

If anyone knows a better way than this, I would very much appreciate your answer - or if you know why the remainder of my forceCheck function might not run...

Stephen
Just a few thoughts here: 1. why not move the "onclick" and put that in a jquery.click event in javascript code instead of embedding it in the markup. 2. I am a bit confused in that it almost seems like a confusion of "validation" vs 'autocomplete" which is typically centered around user interaction within that field itself. 3. consideration for interuption of the submit event, and manually envoking that once you have finished processing the validation.
Mark Schultheiss
1. Is that a better way to do it? I'm not that familiar with web 'best practices'. 2. I am a bit confused about what you're confused about. Can you clarify exactly what you mean by "validation" vs "autocomplete"? 3. Here I'm totally lost. What do you mean?
Stephen
A: 

Hi Stephen,

Apparently, jquery-ui 1.8.4 sort of fixes the problem (see changelog):

  • Fixed: Combobox/Autocomplete doesn't save value unless control loses focus

Have you been able to test it? Because it doesn't work for me.

Jonas