10

I want to do something when a keypress changes the input of a textbox. I figure the keypress event would be best for this, but how do I know if it caused a change? I need to filter out things like pressing the arrow keys, or modifiers... I don't think hardcoding all the values is the best approach.

So how should I do it?

mpen
  • 272,448
  • 266
  • 850
  • 1,236

4 Answers4

24

In most browsers, you can use the HTML5 input event for text-type <input> elements:

$("#testbox").on("input", function() {
    alert("Value changed!");
});

This doesn't work in IE < 9, but there is a workaround: the propertychange event.

$("#testbox").on("propertychange", function(e) {
    if (e.originalEvent.propertyName == "value") {
        alert("Value changed!");
    }
});

IE 9 supports both, so in that browser it's better to prefer the standards-based input event. This conveniently fires first, so we can remove the handler for propertychange the first time input fires.

Putting it all together (jsFiddle):

var propertyChangeUnbound = false;
$("#testbox").on("propertychange", function(e) {
    if (e.originalEvent.propertyName == "value") {
        alert("Value changed!");
    }
});

$("#testbox").on("input", function() {
    if (!propertyChangeUnbound) {
        $("#testbox").unbind("propertychange");
        propertyChangeUnbound = true;
    }
    alert("Value changed!");
});
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Cool! Didn't know about these events. I'd like to support older browsers though :( – mpen Jun 27 '11 at 17:16
  • 2
    @Mark: For text ``s, you're OK in pretty much everything major with this: Safari 3+, all Chrome, Firefox 2+, IE 6+ (possibly even 5), Opera something like 9+. For textareas, the support is not quite as good. – Tim Down Jun 27 '11 at 22:00
  • @Mark: By the way, this is a favourite topic of @Andy E (http://stackoverflow.com/users/94197/andy-e), who has answered several related questions on SO and blogged about it: http://whattheheadsaid.com/projects/input-special-event and http://whattheheadsaid.com/2010/09/effectively-detecting-user-input-in-javascript. – Tim Down Jun 27 '11 at 22:04
  • The "input" event is supported that far back?? Why don't more people know about this? That's crazy. – mpen Jun 27 '11 at 22:43
  • @Mark: Well, it's under 5 years since Firefox 2, but I agree it is surprising it's not more well known. – Tim Down Jun 27 '11 at 23:20
  • @Tim: Probably because there's almost no documentation on it. First 5 hits or so on Google mentioned every event *except* that one. – mpen Jun 28 '11 at 00:03
  • This event does not tell you which keyCode was inputed..actually it gives no information on anything – vsync Mar 01 '13 at 16:42
  • @vsync: You're right, but it's still very useful. Its usefulness is in when it fires rather than what data it carries with it. – Tim Down Mar 01 '13 at 17:35
  • @tim-down - does this approach work on DOM elements such as div or span? – henrywright Jan 12 '14 at 20:34
  • 1
    @henrywright: Using contenteditable, I guess? Recent Mozilla and WebKit have the `input` event on contenteditable elements. IE does not. I'm guessing Opera may well do now that it uses WebKit. See also http://stackoverflow.com/questions/1391278/contenteditable-change-events – Tim Down Jan 12 '14 at 22:34
  • Thanks @tim-down, and Yes, I'm using contenteditable. My aim is to strip tags on pasting in a contenteditable region when using IE. 'input' isn't supported as you say. Was looking for an alternative solution. Does 'propertychange' work only on input elements? – henrywright Jan 13 '14 at 02:07
  • @henrywright: `propertychange` does work on all elements in IE but not well enough. For example, you could listen for changes on `innerHTML` but the `propertychange` event would only fire when `innerHTML` is changed explicitly rather than whenever the DOM within the element changes because of user interaction. All browsers support the `paste` event though, and there are possibilities also with DOM mutation events/observers. – Tim Down Jan 13 '14 at 09:22
8

.change() is what you're after

$("#testbox").keyup(function() {
   $(this).blur();
   $(this).focus(); 
   $(this).val($(this).val()); // fix for IE putting cursor at beginning of input on focus
}).change(function() {
   alert("change fired");
});
Jason Miesionczek
  • 14,268
  • 17
  • 76
  • 108
  • 4
    `.change()` doesn't fire until the textbox loses focus. It sounds like he wants to be notified on keypress. – spb Jun 27 '11 at 02:58
  • he might be able to work around that by adding a keypress event that does a blur()/focus() – Jason Miesionczek Jun 27 '11 at 03:00
  • @spb: check out my jsfiddle, shows an example of the workaround i mentioned above – Jason Miesionczek Jun 27 '11 at 03:04
  • That works well. You should move that jsfiddle into your answer. – spb Jun 27 '11 at 03:07
  • which version of IE? I tested the fiddle in IE7, 8 and 9 using the IE9 dev tools. – Jason Miesionczek Jun 27 '11 at 03:43
  • @Jason: IE 9.0.8112.16421. Did you try my version? The event fires but it moves the cursor back to the start of the input. Kinda completely ruins it. – mpen Jun 27 '11 at 03:46
  • txet gnisrever rof taerg s'ti ,edis thgirb eht nO – mpen Jun 27 '11 at 03:55
  • @Jason: Still doesn't work well. First thing I tried doing was hitting Ctrl+A to select all the text in the input so that I could start typing over it, but you're `.val()` trick just puts it back so I can't actually delete it! – mpen Jul 18 '11 at 00:33
2

This is how I would do it: http://jsfiddle.net/JesseAldridge/Pggpt/1/

$('#input1').keyup(function(){
    if($('#input1').val() != $('#input1').attr('prev_val'))
        $('#input2').val('change')
    else
        $('#input2').val('no change')
    $('#input1').attr('prev_val', $('#input1').val())
})
Jesse Aldridge
  • 7,991
  • 9
  • 48
  • 75
  • 1
    Should use `.data` instead of `.attr` but I think this approach is good too. – mpen Jun 27 '11 at 03:35
  • You could make that a bit more flexible by changing all the $("#input1") to $(this) (within the event handler) – Jason Miesionczek Jun 27 '11 at 03:40
  • 1
    @Jason: That too. Was thinking the same thing. http://jsfiddle.net/mnbayazit/WCmSn/ – mpen Jun 27 '11 at 03:47
  • 1
    It's also possible to bypass the keyup event if you hold down a letter key while inside the textbox, and then click outside. Not likely...but still an event that should be guarded against. Need to combine with `.change` I think for robustness. Also, this won't fire for each letter than is entered during a long keypress, just once at the end. Which is fine in my case, but...kinda sad that I don't think there's anything we can do about that. – mpen Jun 27 '11 at 03:53
  • @Mark - it's also possible to bypass *all* key events if you use the mouse to cut, paste, delete or drop. (Though you did already mention combining with the change event so you should be OK.) Also, you mention `keyup` not firing for each letter if you hold down a key, but `keypress` should. – nnnnnn Jun 27 '11 at 05:57
  • @nnnnn: Yes, but keypress fires *before* the input is updated. That causes problems. – mpen Jun 28 '11 at 00:00
0

I came up with this for autosaving a textarea. It uses a combination of the .keyUp() jQuery method to see if the content has changed. And then I update every 5 seconds because I don't want the form getting submitted every time it's changed!!!!

var savePost = false;

jQuery(document).ready(function() { 
    setInterval('autoSave()', 5000)
    $('input, textarea').keyup(function(){
        if (!savePost) {
            savePost = true;    
        }
    })
})


function autoSave() {
    if (savePost) {
        savePost = false;
        $('#post_submit, #task_submit').click();            
    }
}

I know it will fire even if the content hasn't changed but it was easier that hardcoding which keys I didn't want it to work for.

thenengah
  • 42,557
  • 33
  • 113
  • 157
  • Err..that's not really what I asked. I'm not trying to build an autosave feature, so this doesn't really work for me at all. – mpen Jun 27 '11 at 03:37