Google Chrome change event in input is not fired if char added on keyup
Asked Answered
B

5

7
$('input#not-gonna-work').bind({
    keyup: function(){
        console.log('Typed a key');
        $(this).val($(this).val() + '.');// try with any other char
    },
    change: function(){
       console.log('I\'m a changed input');
    }
});

I staged this bug in this simplified jsfiddle example. My problem related to this bug is that I have a financial app that I'm building and I need to display a "Save changes" button if input data is changed. Since I need to insert thousand separator immediately on keyup (if needed) this bug really annoys me and breakes that functionality.

To reproduce it go to jsfiddle example, open console in chrome type anything in first input, keyup event will be properly fired, than un-focus input with tab or clicking outside of it and change event won't be fired. Do the same with other input and change will be fired.

I tested this in Firefox and it works as expected.

Version of Chromium that I'm using is 14.0.835.202 (Developer Build 103287 Linux) Ubuntu 11.10

and

Tried with Google Chrome 15.0.874.106 freshly installed straight from Chrome website.

I could insert separators on change event, but since users will be entering lots of 7+ digits numbers it would much better UX to have separators inserted as they type.

Bigoted answered 30/10, 2011 at 16:14 Comment(2)
Better UX? It adds a period everytime I try to delete? Is that part of the functionality requirements?Phalanstery
@wirey - I don't think that level of code is pertinent to this question. Including that in the example code would it made it more difficult to trace the core problem.Schapira
O
8

I tried it in IE9 and it has the same behavior as Chrome.

I don't think it's a bug.

Using .val(value) on an HTML element will reset the "manually changed" flag and thus no change event will occur (because the user doesn't change anything manually AFTER the val() operation).

Orsa answered 20/9, 2012 at 10:22 Comment(8)
So what you are saying is basically this: first user enters some char, than js intercepts keyup and changes value and invalidates manually changed flag and no change event is fired? Can manually changed flag be set from js? Do you have any sources that confirm this?Bigoted
Read: "The onchange event does not fire when the selected option of the select object is changed programmatically."Orsa
The solution could be using blur() event instead of change()Orsa
Isn't that about select? Does it apply also on input?Bigoted
That phrase is ambiguous, but the paragraph before mentions both text inputs and select fields.Orsa
Yeah, I'll look more into it later.Bigoted
+1 for relevant documentation (even if it's a different browser)Schapira
@IvanIvanić Please try blur() instead of change()Orsa
S
7

This looks like a valid Chrome bug. My guess is that changing the value resets whatever Chrome relies on to trigger the onChange event since the user last focused on the input. I would suggest using a workaround (unfortunately) that should work in all browsers.

I've updated your code with such an example here. The idea is that you store the original value when the input receives focus, then compare the original value to the updated value when the input is blurred. If it is a different value, then perform the same logic that you would have put into your change callback.

Schapira answered 14/9, 2012 at 18:44 Comment(3)
Yeah, I'm already doing something similar, except that I fire change event on every keyup and than do the check for changed value. Thanks for idea. I submitted report to Chrome team before year or so but no answer until now. I am now really interested if there is some other explanation than "It is a bug" :)Bigoted
When you trigger the change event manually, do you end up with it being double-triggered on browsers where it works as expected? I would anticipate the code I proposed wouldn't have this problem. Good luck figuring it out. :)Schapira
I ran into the same issue once for a select box. My solution was indeed to trigger the change manually, resulting in double triggers in some browsers.Botti
H
4

It seems this behavior is expected. (See http://dev.w3.org/html5/spec/common-input-element-apis.html#event-input-change).

It mentions that if you programmatically change the value, you have to manually fire the event.

And according to https://developer.mozilla.org/en-US/docs/DOM/element.onchange, Mozilla implements change as follows:

  control.onfocus = focus;
  control.onblur = blur;
  function focus () {
      original_value = control.value;
  }

  function blur () {
      if (control.value != original_value)
        control.onchange();
  }

For now, you can capture the blur event and fire 'change' event from there. (You may want check your before and after values before calling change() as done by Mozilla.)

blur: function(){
   $(this).change();
}
Homologize answered 21/9, 2012 at 19:39 Comment(0)
O
1

That seems to be the behavior to me.. If the value of an element is changed via script then your onchange will not be triggered. In such cases you need to save the value onfocus and check the value onblur and trigger onchange manually.

See below,

DEMO: http://jsfiddle.net/vCxme/6/

$('input#not-gonna-work').bind({
    keyup: function(){
        console.log('Typed a key');
        $(this).val($(this).val() + '.');
    },
    change: function(){
       console.log('I\'m a changed input');
    },
    focus: function ( ){
        $(this).data('orig_value', $(this).val());
    },
    blur: function () {
        if ($(this).val() != $(this).data('orig_value')){
            $(this).change();
        }
    }
});
$('input#gonna-work').bind({
    keyup: function(){
        console.log('Typed a key');
    },
    change: function(){
       console.log('I\'m a changed input');
    }
});

The above implementation is from pseudo code as from FF onChange

Note: The browser change event will not be triggered when the value is changed via script.

Osugi answered 21/9, 2012 at 15:33 Comment(0)
L
0

I would approach from a slightly different angle (so work around), of checking the value of the field every time a keyup event is performed. See http://jsfiddle.net/vCxme/3/

Lollop answered 21/9, 2012 at 11:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.