Andrew
Andrew

Reputation: 43123

jQuery bind to keyup only, not focus

This seems like a simple thing but google hasn't turned up anything for me:

How can I bind to a text / value change event only, excluding an input gaining focus? Ie, given the following:

$(function(){
  $('input#target').on('keyup', function(){
    alert('Typed something in the input.');
  });
});

...the alert would be triggered when the user tabs in and out of an element, whether they actually input text or not. How can you allow a user to keyboard navigate through the form without triggering the event unless they input/change the text in the text field?

Note: I'm showing a simplified version of a script, the reason for not using the change event is that in my real code I have a delay timer so that the event happens after the user stops typing for a second, without them having to change focus to trigger the event.

Upvotes: 5

Views: 8695

Answers (4)

morne
morne

Reputation: 4189

Here is another version that plainly tests if the input field is empty.

If the input is empty then the action is not performed.

$(function(){
    $(selector).on('keyup', function(){
        if ($(this).val()!='') {
            alert('char was entered');
        }
    })
});

Upvotes: 0

Jon
Jon

Reputation: 437424

Simply use the .change event.

Update: If you want live change notifications then do you have to go through the keyup event, which means that you need to program your handler to ignore those keys that will not result in the value being modified.

You can implement this with a whitelist of key codes that are ignored, but it could get ugly: pressing Del results in the value being changed, unless the cursor is positioned at the end of the input in which case it does not, unless there happens to be a selected range in the input in which case it does.

Another way which I personally find more sane if not as "pure" is to program your handler to remember the old value of the element and only react if it has changed.

$(function() {
    // for each input element we are interested in
    $("input").each(function () {
        // set a property on the element to remember the old value,
        // which is initially unknown
        this.oldValue = null;
    }).focus(function() {
        // this condition is true just once, at the time we
        // initialize oldValue to start tracking changes
        if (this.oldValue === null) {
            this.oldValue = this.value;
        }
    }).keyup(function() {
        // if no change, nothing to do
        if (this.oldValue == this.value) {
            return;
        }

        // update the cached old value and do your stuff
        this.oldValue = this.value;
        alert("value changed on " + this.className);
    });
});​

If you do not want to set properties directly on the DOM element (really, there's nothing wrong with it) then you could substitute $(this).data("oldValue") for this.oldValue whenever it appears. This will technically have the drawback of making the code slower, but I don't believe anyone will notice.

See it in action.

Upvotes: 4

adeneo
adeneo

Reputation: 318242

Store the value, and on any key event check if it's changed, like so:

$(function(){
  $('input#target').on('keyup', function(){
      if ($(this).data('val')!=this.value) {
          alert('Typed something in the input.');
      }
      $(this).data('val', this.value);
  });
});​

FIDDLE

Upvotes: 6

Silviu-Marian
Silviu-Marian

Reputation: 10907

This will do it, set a custom attribute and check against that:

$('input').focus(function(){ 
    $(this).attr('originalvalue',$(this).val()); 
});

$('input').on('keyup',function(){ 
    if($(this).val()===$(this).attr('originalvalue')) return; 
    alert('he must\'ve typed something.'); 
});

Be wary of events firing multiple times.

Upvotes: 1

Related Questions