404

The logic in the change() event handler is not being run when the value is set by val(), but it does run when user selects a value with their mouse. Why is this?

<select id="single">
    <option>Single</option>
    <option>Single2</option>
</select>

<script>
    $(function() {
        $(":input#single").change(function() {
           /* Logic here does not execute when val() is used */
        });
    });

    $("#single").val("Single2");
</script>
Kunj
  • 1,980
  • 2
  • 22
  • 34
Eric Belair
  • 10,574
  • 13
  • 75
  • 116

10 Answers10

631

Because the change event requires an actual browser event initiated by the user instead of via javascript code.

Do this instead:

$("#single").val("Single2").trigger('change');

or

$("#single").val("Single2").change();
Milind Anantwar
  • 81,290
  • 25
  • 94
  • 125
user113716
  • 318,772
  • 63
  • 451
  • 440
  • 1
    Hi, doing this update drop down. but getting called onChange() recursively. – Pankaj Nov 14 '14 at 08:51
  • 3
    I dig this answer. It works, but isn't there a better way with jQuery? I'm sure we will ALL remember to do this every time we change a value that has an change handler set up (sarcasm). Frameworks that use data binding might solve this better? – Jess Oct 08 '15 at 14:04
  • @user113716 would you know how to tigger it without knowing any values? – BenKoshy Jul 26 '16 at 06:41
  • 4
    I agree this is the correct answer but this absolutely sucks and ruins what I am trying to do. – Dustin Poissant Nov 19 '16 at 13:56
  • Try $("#single").trigger({type: "change", val: "Single2"}) – user2901633 Jun 24 '19 at 05:41
48

I believe you can manually trigger the change event with trigger():

$("#single").val("Single2").trigger('change');

Though why it doesn't fire automatically, I have no idea.

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • I am not able to get working this, also $("#single").val("Single2").change(); I am dynamically creating dropdown and changing its value ( Its working fine for me) But when I am trying to trigger change its not working for me. – Maneesh Kumar Sep 19 '13 at 11:16
  • 5
    A "bit" belated but it doesn't fire automatically because it would lead to infinite loops. Think `$('#foo').change(function() { $( this ).val( 'whatever' ); });` – JJJ Jun 28 '14 at 10:21
  • @Juhana I think an infinite loop is much easier to notice, diagnose and fix than val() mysteriously failing to trigger "change" bindings. – iono Sep 05 '16 at 08:27
  • Calling .change() is shorthand for calling .trigger('change'). – Triynko Nov 30 '16 at 19:42
10

Adding this piece of code after the val() seems to work:

$(":input#single").trigger('change');
Eric Belair
  • 10,574
  • 13
  • 75
  • 116
  • 6
    Yes, but you don't need to do a separate DOM selection for it with `$(":input#single")`. In fact you really shouldn't. Just chain it after the `.val()`. You can use `.trigger('change')` or `.change()`. They are the exact same. – user113716 Jan 12 '11 at 18:41
8

As far as I can read in API's. The event is only fired when the user clicks on an option.

http://api.jquery.com/change/

For select boxes, checkboxes, and radio buttons, the event is fired immediately when the user makes a selection with the mouse, but for the other element types the event is deferred until the element loses focus.

Marnix
  • 6,384
  • 4
  • 43
  • 78
  • What are the alternatives for the other element types? I want the 'change' event to fire immediately for `input` elements, not when the element loses focus. Do you know? – Dan Nissenbaum Apr 11 '15 at 22:01
  • 1
    If by "immediately" you mean "whenever a key is pressed in the input" you're looking for the onkeyup, onkeypress, and onkeydown events, not onchange. – user2867288 Mar 16 '16 at 15:51
7

To make it easier, add a custom function and call it whenever you want to change the value and also trigger a change:

$.fn.valAndTrigger = function (element) {
    return $(this).val(element).trigger('change');
}

and

$("#sample").valAndTrigger("NewValue");

Or you can override the val() function to always call the change when val() is called:

(function ($) {
    var originalVal = $.fn.val;
    $.fn.val = function (value) {
        this.trigger("change");
        return originalVal.call(this, value);
    };
})(jQuery);

Sample at http://jsfiddle.net/r60bfkub/

pbarney
  • 2,529
  • 4
  • 35
  • 49
Alireza Fattahi
  • 42,517
  • 14
  • 123
  • 173
  • My browser complains of too much recursion, any fix for this? – Bhargav Nanekalva May 23 '17 at 15:04
  • You are listening for the ```change```-event over a control and executing a callback that (directly or indirectly) triggers again the ```change```-event over the same control. I suggest you to use another name for the event that you trigger manually (e.g. ```explicit.change```), so that it doesn't re-trigger the ```change```-event, prevents the loop, and still allows you to react to the event. – Kamafeather Jan 24 '18 at 17:31
3

In case you don't want to mix up with default change event you can provide your custom event

$('input.test').on('value_changed', function(e){
    console.log('value changed to '+$(this).val());
});

to trigger the event on value set, you can do

$('input.test').val('I am a new value').trigger('value_changed');
codingrhythm
  • 1,456
  • 14
  • 26
3

If you've just added the select option to a form and you wish to trigger the change event, I've found a setTimeout is required otherwise jQuery doesn't pick up the newly added select box:

window.setTimeout(function() { jQuery('.languagedisplay').change();}, 1);
Dave Hilditch
  • 5,299
  • 4
  • 27
  • 35
3

I ran into the same issue while using CMB2 with Wordpress and wanted to hook into the change event of a file upload metabox.

So in case you're not able to modify the code that invokes the change (in this case the CMB2 script), use the code below. The trigger is being invoked AFTER the value is set, otherwise your change eventHandler will work, but the value will be the previous one, not the one being set.

Here's the code i use:

(function ($) {
    var originalVal = $.fn.val;
    $.fn.val = function (value) {
        if (arguments.length >= 1) {
            // setter invoked, do processing
            return originalVal.call(this, value).trigger('change');
        }
        //getter invoked do processing
        return originalVal.call(this);
    };
})(jQuery);
  • This is good, but can you show how you would limit it to just one particular input? – jwebb Jul 20 '18 at 15:33
  • @jwebb Not quite sure what you mean? We're overriding the jQuery val() function. You bind a change event handler to a specific input. – user2075039 Sep 13 '18 at 14:07
  • I mean, @user2075039, what if there are multiple inputs on the page using the jQuery val() function and you don't want to bind the custom change event handler to ALL of them but just one of them? – jwebb Sep 14 '18 at 03:51
  • @jwebb you can check `this.selector` inside the overriding `$.fn.val` function, for a specific selector (will be dependent on what is used for the selector). This is the best i've found for doing this only for specific fields, only problem is you must know what they are using for the selector – sMyles Oct 22 '19 at 17:33
1
$(":input#single").trigger('change');

This worked for my script. I have 3 combos & bind with chainSelect event, I need to pass 3 values by url & default select all drop down. I used this

$('#machineMake').val('<?php echo $_GET['headMake']; ?>').trigger('change');

And the first event worked.

Tom van der Woerdt
  • 29,532
  • 7
  • 72
  • 105
  • 10
    I hope, you never do this in real world. Needless to say that $_GET['whatever'] cannot be trusted. – Denis V Sep 13 '13 at 18:57
0

To change the value

$("#single").val("Single2");

Also to trigger a change event

$("#single").val("Single2").change();

this logic is instrumental when multiple select options are on a page.
one changes and other select options have to change but do not trigger a change event.

bhv
  • 5,188
  • 3
  • 35
  • 44