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?

mikemaccana
  • 110,530
  • 99
  • 389
  • 494

7 Answers7

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;
})();
adamdport
  • 11,687
  • 14
  • 69
  • 91
mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • 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. – tfrascaroli Jun 02 '16 at 07:54
  • 7
    In IE11 it seems to be safe to set window.Event = CustomEvent, yes. – Corey Alix Oct 28 '16 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 Jan 11 '17 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 Apr 12 '17 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 Apr 13 '17 at 05:41
  • In IE you need to place this block of code at the very top before it is needed for instantiation. – Andrei Bazanov Sep 29 '17 at 13:37
  • Refer here https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent – Ramanathan Ganesan Feb 27 '18 at 04:26
  • I had to to some adjustments, but this is definitely the solution. Saved my day. Thanks. – Sampgun Oct 17 '18 at 12:02
  • I noticed the polyfill on MDN doesn't have this line: `CustomEvent.prototype = window.Event.prototype;` -- what's the purpose of adding this line? – thdoan Oct 23 '19 at 02:07
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;
}
T3rm1
  • 2,299
  • 5
  • 34
  • 51
michalduda
  • 738
  • 5
  • 7
  • 3
    It works! I just think it should `return event` so I can pass it to `dispatchEvent()`. – Noumenon Feb 19 '17 at 14:33
  • `initEvent` is old and [deprecated](https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent), you need to at least use the modern way and as a fallback, use the deprecated way. – vsync Oct 24 '17 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 Dec 20 '17 at 00:42
  • 1
    `CustomEvent` allows to pass custom data through `detail` option, and `Event` doesn't. Am I wrong? – pttsky Apr 02 '18 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. – UndyingJellyfish Jan 22 '19 at 09: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'))
fsavina
  • 370
  • 4
  • 10
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);
Patrick Dark
  • 2,187
  • 1
  • 20
  • 23
  • 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 Oct 24 '17 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. – Patrick Dark Oct 25 '17 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 Oct 26 '17 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);
Liran H
  • 9,143
  • 7
  • 39
  • 52
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>
frumbert
  • 2,323
  • 5
  • 30
  • 61
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... */]).

Kevin Drost
  • 383
  • 4
  • 7