1

I have a bit of JavaScript that builds some HTML for me and inserts it into a div. I am using jQuery 1.7.2 for this test.

I'm interested in attaching a custom change or keyup event handler on an input text field called gene_autocomplete_field.

Here's what I have tried so far.

The following function builds the HTML, which is inserted into a div called gene_container:

function buildGeneContainerHTML(count, arr) {
    var html = "";
    // ...
    html += "<input type='text' size='20' value='' id='gene_autocomplete_field' name='gene_autocomplete_field' placeholder='Enter gene name...' /><br/>";
    // ...
    return html;
}

// ...
$('#gene_container').html( buildGeneContainerHTML(count, geneNameArr) );

In my calling HTML, I grab the gene_autocomplete_field from the gene_container element, and then I override the keyup event handler for gene_autocomplete_field:

<script>
    $(document).ready(function() {
        $("#gene_container input:[name=gene_autocomplete_field]").live('keyup', function(event) {
            refreshGenePicker($("#gene_container input:[name=gene_autocomplete_field]").val());
        });
    });
</script>

When I change the text in gene_autocomplete_field, the refreshGenePicker() function just sends an alert:

function refreshGenePicker(val) {
    alert(val);
}

Result

If I type any letter into the gene_autocomplete_field element, the event handler seems to call alert(val) an infinite number of times. I get one alert after another and the browser gets taken over by the dialog boxes. The value returned is correct, but I worry that refreshGenePicker() gets called over and over again. This is not correct behavior, I don't think.

Questions

  • How do I properly capture the keyup event once, so that I only handle a content change to the autocomplete field the one time?
  • Is there a different event I should use for this purpose?

UPDATE

It turns out that more than just a keyCode of 13 (Return/Enter) can be an issue — pressing Control, Alt, Esc or other special characters will trigger an event (but will be asymptomatic, as far as the infinite loop issue goes). The gene names I am filtering on do not have metacharacters in them. So I made use of an alphanumeric detection test to filter out non-alphanumeric characters from further event handling, which includes the Return key:

if (!alphaNumericCheck(event.keyCode)) return;
Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345

3 Answers3

5

alert is called infinite times because you use the 'Enter' key to confirm/dismiss the alert. Use .on('change') instead. This will prevent refreshGenePicker from being called when you use enter in an alert.

However, the 'change' event will only trigger if the input element looses focus. If you want to use refreshGenePicker on every key, use the following approach instead:

$("#gene_container input:[name=gene_autocomplete_field]").live('keyup', function(event) {
    if(event.keyCode === 13) // filter ENTER
        return;
    refreshGenePicker($("#gene_container input:[name=gene_autocomplete_field]").val());
});

This will filter any incoming enter keyup events (jsFiddle demo). Also switch to .on and drop .live.

EDIT: Note that there are more possibilities to dismiss an alert modal, such as the escape or space key. You should add a check inside your refreshGenePicker whether the value has actually changed.

Zeta
  • 103,620
  • 13
  • 194
  • 236
  • Hmmmz On what browser is that return capture on the textfield? Cannot reproduce it on Chrome. – PeeHaa Apr 01 '12 at 13:32
  • I am testing both Safari 5.1.5 and Chrome 18.0.1025.142. – Alex Reynolds Apr 01 '12 at 13:33
  • I'm on Chrome 20 maybe that's it. Thanks! But I still think it's odd behavior, but hey what you gonna do :) – PeeHaa Apr 01 '12 at 13:34
  • @RepWhoringPeeHaa: Firefox and Opera on Windows are behaving the same. Internet Explorer 9 doesn't care about it, but it's a little bit slow (I can type asdfghj before the event gets fired). The joys of event propagation in interrupting JavaScript methods (`prompt`, `confirm`, `alert`) :). – Zeta Apr 01 '12 at 13:36
  • @RepWhoringPeeHaa - Just updated your fiddle and reproduced in Chrome. – Anthony Apr 01 '12 at 13:37
  • @Zeta - Nice catch! How incredibly stupid, though. The keypress for the dialog is not a keypress event for the target field, obviously. Is there anywhere in the DOM where this gets distinguished? – Anthony Apr 01 '12 at 13:39
  • 1
    @Anthony: http://www.w3.org/TR/DOM-Level-3-Events/#dom-event-architecture - however, a modal dialog gets canceled by a `keydown`, it doesn't wait for a keyup signal. Try it for yourself in the first demo, just keep enter/esc/space pressed. – Zeta Apr 01 '12 at 13:48
  • @Zeta - I saw it, I just am dumbfounded. So because the keyup is left lingering, the field is technically back in focus and thus catching it? Since most of us stray from `alert` unless we're testing, is this something that has implications outside of this scenario? – Anthony Apr 01 '12 at 14:09
  • @Anthony huh? In my Chrome is still works as expected. Without infinite alerts. I say Yay! for latest Chrome? – PeeHaa Apr 01 '12 at 14:11
  • @Zeta - Actually, what this reminds me of is the auto-complete feature in browsers (specifically Chrome) where you have to press Enter (as opposed to right arrow or tab) to get it to select that choice, even though hitting enter inside a form is a habit everyone has learned to break, having submitted too many forms before their time. This is the exact opposite but just as counter-intuitive. – Anthony Apr 01 '12 at 14:13
  • @RepWhoringPeeHaa - Well I'm on Chrome 18, the latest non-dev/nightly, so maybe this has been addressed? Do they have a decent Update log we can check? I'd love to see if they actually acknowledge the issue (or maybe it's a newer WebKit fix?) – Anthony Apr 01 '12 at 14:15
1

You should really use .on() if you are using jQuery > 1.7.

Check out the perftest.

And also check out my some what related question.

Also when testing equal you should really add quotes around it:

input:[name='gene_autocomplete_field']

To answer you real question :). It shouldn;t behave like that with the code you have presented. Maybe something else is wrong. Can you setup a jsfiddle with the issue?

Check out my demo and perhaps you see what's wrong with your code:

function refreshGenePicker(value) {
    console.log('keyup! Value is now: ' + value);
}

(function($) {
    var someHtml = '<input type="text" name="gene_autocomplete_field">';
    $('body').append(someHtml);

    $('body').on('keyup', 'input[name="gene_autocomplete_field"]', function(e) {
        refreshGenePicker($(this).val());
    });
})(jQuery);​
Community
  • 1
  • 1
PeeHaa
  • 71,436
  • 58
  • 190
  • 262
-1
$(document).ready(function() {
    $('#test').html('<input id="text" />');
    $('#text').keyup(function() {
        console.log($(this).val());
    });
});​

This works just fine. Since you've got our second code block in <script> tags, you might be running it more than once - which would cause it to bind more than once and produce more than one alert each time it is bound. You could of course use .unbind() on that input before adding the keyup, but I think a much better solution would be to group all the code in a single $(document).ready(); to ensure you're only binding the object once.

http://jsfiddle.net/Ka7Ty/2/

Aram Kocharyan
  • 20,165
  • 11
  • 81
  • 96