141

I am creating an event, so use the DOM Event constructor:

new Event('change');

This works fine in modern browsers, however in Internet Explorer 9, 10 & 11, it fails with:

Object doesn't support this action

How can I fix Internet Explorer (ideally via a polyfill)? If I can't, is there a workaround I can use?

1
  • 61
    "how can I fix Internet Explorer?" xD Commented Sep 5, 2017 at 1:16

7 Answers 7

187

There's an IE polyfill for the CustomEvent constructor at MDN. Adding CustomEvent to IE and using that instead works.

(function () {
  if ( typeof window.CustomEvent === "function" ) return false; //If not IE

  function CustomEvent ( event, params ) {
    params = params || { bubbles: false, cancelable: false, detail: undefined };
    var evt = document.createEvent( 'CustomEvent' );
    evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
    return evt;
   }

  CustomEvent.prototype = window.Event.prototype;

  window.CustomEvent = CustomEvent;
})();
9
  • 14
    You sir saved my life. Would it be safe to make a complete substitution? I mean, doing window.Event= CustomEvent on the last line. Commented Jun 2, 2016 at 7:54
  • 7
    In IE11 it seems to be safe to set window.Event = CustomEvent, yes.
    – Corey Alix
    Commented Oct 28, 2016 at 18:01
  • 10
    For anybody interested it seems to be possible to detect you are in IE (for this case) by checking typeof(Event) which is 'function' for all except IE where it is 'object'. You can then safely polyfill the Event constructor using the approach above.
    – Euan Smith
    Commented Jan 11, 2017 at 14:55
  • I'm just investigating similar workaround for StorageEvent and typeof(StorageEvent) doesn't work in MS Edge. This works: try { new StorageEvent(); } catch (e) { /* polyfill */ }.
    – kamituel
    Commented Apr 12, 2017 at 14:18
  • 1
    It might not be safe to substitute window.CustomEvent, if you are using third party libraries which uses IE defined CustomEvent constructor.
    – Sen Jacob
    Commented Apr 13, 2017 at 5:41
68

I think that the best solution to solve your problem and deal with cross-browser event creation is:

function createNewEvent(eventName) {
    var event;
    if (typeof(Event) === 'function') {
        event = new Event(eventName);
    } else {
        event = document.createEvent('Event');
        event.initEvent(eventName, true, true);
    }
    return event;
}
5
  • 3
    It works! I just think it should return event so I can pass it to dispatchEvent().
    – Noumenon
    Commented Feb 19, 2017 at 14:33
  • initEvent is old and deprecated, you need to at least use the modern way and as a fallback, use the deprecated way.
    – vsync
    Commented Oct 24, 2017 at 11:07
  • 3
    @vsync It might be deprecated, but the docs you linked to say "Instead use specific event constructors, like Event()", which is exactly what this is trying to polyfill, so there's no choice really.
    – reduckted
    Commented Dec 20, 2017 at 0:42
  • 1
    CustomEvent allows to pass custom data through detail option, and Event doesn't. Am I wrong?
    – pttsky
    Commented Apr 2, 2018 at 12:53
  • 1
    CustomEvent is not supported for IE9, 10 or 11 either per my own experience. The only good answer seems to be the accepted. Commented Jan 22, 2019 at 9:26
4

This package does the magic:

https://www.npmjs.com/package/custom-event-polyfill

Include the package and dispatch the event as following:

window.dispatchEvent(new window.CustomEvent('some-event'))
3
  • 95 dependencies?
    – user419017
    Commented Jul 25, 2018 at 9:22
  • 6
    @DamienRoche Could it be you missread "Dependents" as "Dependencies"? Because the package actually has 0 dependencies and (by the time of writing) 102 dependents (i.e., packages that depend on it). That 102 dependent packages probably were 95 back in july.
    – flu
    Commented Oct 16, 2018 at 8:43
  • 3
    I bloody well did! :P
    – user419017
    Commented Oct 16, 2018 at 9:56
3

If you're just trying to dispatch a simple event like the HTML toggle event, this works in Internet Explorer 11 as well as the other browsers:

let toggle_event = null;
try {
    toggle_event = new Event("toggle");
}
catch (error) {
    toggle_event = document.createEvent("Event");
    let doesnt_bubble = false;
    let isnt_cancelable = false;
    toggle_event.initEvent("toggle", doesnt_bubble, isnt_cancelable);
}
// disclosure_control is a details element.
disclosure_control.dispatchEvent(toggle_event);
3
  • 6
    can't see why you are mixing es6 let (and not use var) with a code supposed to run on old IE.. it might confuse beginners who will copy-paste this
    – vsync
    Commented Oct 24, 2017 at 11:12
  • 1
    @vsync shrug I did mention the version number. My personal website was only targeting IE11 last year, so it never occurred to me to check support in older versions. (As of today, I serve IE11 plain HTML without stylesheets or scripts. People need to move on.) In any case, the only version of Internet Explorer still supported by Microsoft as of 2017 April is version 11, so it's a bit of a moot point. I’d not encourage anyone to use an unsupported browser by targeting it. The Web can be a dangerous place. Commented Oct 25, 2017 at 20:04
  • 5
    it's not about that at all, and not about trying to change the world or anything. For example, the title for the question specifically asks for IE 9 and above, and perhaps a person seeking an answer who finds this thread, is developing an app for legacy banking system or some other system for business clients which have no control over their computers and are obliged to work with old IE. this has nothing to do with Microsoft Support..
    – vsync
    Commented Oct 26, 2017 at 10:49
3

the custom-event npm package worked beautifully for me

https://www.npmjs.com/package/custom-event

var CustomEvent = require('custom-event');

// add an appropriate event listener
target.addEventListener('cat', function(e) { process(e.detail) });

// create and dispatch the event
var event = new CustomEvent('cat', {
  detail: {
    hazcheeseburger: true
  }
});
target.dispatchEvent(event);
3
  • This is a good answer, but there's already another NPM package mentioned as an answer. Commented Jun 15, 2018 at 13:30
  • 2
    What's wrong with giving users a variety of options?
    – Liran H
    Commented Jun 16, 2018 at 17:18
  • A more generic package is npmjs.com/package/events-polyfill Commented May 29, 2019 at 9:10
3

There's a polyfill service which can patch this and others for you

https://polyfill.io/v3/url-builder/

 <script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js"></script>
2

I personally use a wrapper function to handle manually created events. The following code will add a static method on all Event interfaces (all global variables ending in Event are an Event interface) and allow you to call functions like element.dispatchEvent(MouseEvent.create('click')); on IE9+.

(function eventCreatorWrapper(eventClassNames){
    eventClassNames.forEach(function(eventClassName){
        window[eventClassName].createEvent = function(type,bubbles,cancelable){
            var evt
            try{
                evt = new window[eventClassName](type,{
                    bubbles: bubbles,
                    cancelable: cancelable
                });
            } catch (e){
                evt = document.createEvent(eventClassName);
                evt.initEvent(type,bubbles,cancelable);
            } finally {
                return evt;
            }
        }
    });
}(function(root){
    return Object.getOwnPropertyNames(root).filter(function(propertyName){
        return /Event$/.test(propertyName)
    });
}(window)));

EDIT: The function to find all Event interfaces can also be replaced by an array to alter only the Event interfaces you need (['Event', 'MouseEvent', 'KeyboardEvent', 'UIEvent' /*, etc... */]).

Not the answer you're looking for? Browse other questions tagged or ask your own question.