Search code examples
javascriptjqueryonchangedom-events

jQuery $el.trigger('change') doesn't fire native listeners


Consider the following HTML:

<select value="val2">
  <option value="val1">o1</option>
  <option value="val2">o2</option>
</select>

And JavaScript (performed on document ready):

var $select = $('select');
var select = $select.get(0);

function logger(msg) {
    return function () { console.log(msg); };
}

$select.on('change', logger('jquery on select'));
$(document).on('change', logger('jquery on document'));

select.addEventListener('change', logger('native on select'), false);
document.addEventListener('change', logger('native on document'), false);

setTimeout(function () {
    console.log(' == programmatic ==');
    $select.trigger('change');
    console.log(' == now try manual ==');
}, 1000);

This results to the following output in the console:

 == programmatic ==
jquery on select
jquery on document
 == now try manual ==
jquery on select
native on select
jquery on document
native on document 

The question is: why are natively bound listeners not called? How make them be called?

Here's also a jsFiddle: http://jsfiddle.net/PVJcf/

(Using jQuery 2.0.2)


Solution

  • This article gives a good overview of the topic:

    Triggering Event Handlers

    Basically, trigger will only fire event handlers attached through jQuery or certain event handler attributes in the html.

    You can define a plugin to trigger a native browser event like this:

    (function($) {
    
        $.fn.trigger2 = function(eventName) {
            return this.each(function() {
                var el = $(this).get(0);
                triggerNativeEvent(el, eventName);
            });
        };
    
        function triggerNativeEvent(el, eventName){
          if (el.fireEvent) { // < IE9
            (el.fireEvent('on' + eventName));
          } else {
            var evt = document.createEvent('Events');
            evt.initEvent(eventName, true, false);
            el.dispatchEvent(evt);
          }
    }
    
    }(jQuery)); 
    
    // sample usage
    $('select').trigger2('change');
    

    This is not perfect but should give you the general idea.

    Here's an update to your fiddle using this plugin.