Is it possible to extend the EventTarget interface? - javascript

I'm looking for an answer if this is possible, or even a good idea.
Usually, as a fix for IE8 and earlier versions, a workaround similar to this is used:
var addEvent = function(obj, e, cb) {
if(obj.attachEvent) {
return obj.attachEvent('on' + e, cb);
} else {
obj.addEventListener(e, cb, false);
return true;
}
}
and then the programmer would always use addEvent instead of addEventListener.
Is there any way or point to create an addEventListener function that would wrap around the attachEvent when it is undefined?
I imagine it's a bit tricky since the EventTarget can be a DOM element, the document, or the window, or somethign else.

It depends on how far back you want to go. On IE8, you can extend Element.prototype to add features to all HTML elements, which is 90% at least of the work. I'm fairly sure you can't do that in IE6 (PrototypeJS had to resort to extending individual Element instances), I don't remember about IE7. Unless you're targeting east-Asian markets, you can basically ignore IE7 and earlier, though.
Here's an example of how you do that:
(function() {
// Functions for IE
function stopPropagation() {
this.cancelBubble = true;
}
function preventDefault() {
this.returnValue = false;
}
function addEventUsingAttach(eventName, handler)
{
this.attachEvent("on" + eventName, function() {
var e = window.event;
e.stopPropagation = stopPropagation;
e.preventDefault = preventDefault;
handler.call(this, e);
});
}
// Function to add `addEvent` to the given target object
function extendIt(target)
{
if (target.addEventListener) {
target.addEvent = Element.prototype.addEventListener;
}
else {
target.addEvent = addEventUsingAttach;
}
}
// Add it to `Element.prototype` if we have it
if (typeof Element !== "undefined" &&
typeof Element.prototype !== "undefined") {
extendIt(Element.prototype);
}
// Add it to `window` and `document` (etc.)
extendIt(window);
extendIt(document);
})();
Live Example | Source
Then you manually extend the other EventTargets, like window and document (see the end of the code listing above).
Original answer: I originally misread your question to be about adding addEventListener, specifically, on IE8, whereas in fact your question is quite clearly not about adding that, but adding your own addEvent. I'm leaving this answer in place for other readers:
It depends on how far back you want to go. On IE8, you can extend Element.prototype to add addEventListener to it, and that will be used by all HTML elements on the page (see below). The shim you add can't support the capturing phase, though, because IE didn't support it until they supported addEventListener natively. I'm fairly sure you can't extend Element.prototype on earlier versions (IE7, IE6), PrototypeJS had to fall back to extending specific elements for older versions of IE. But it works in IE8.
Having extended Element.prototype, then you'd have to manually extend the other event targets you mentioned, but extending Element.prototype does most of the work.
But if you do this and you include third-party scripts, beware that they may assume a correct implementation of addEventListeneer complete with the capturing phase.
Here's a basic shim for adding addEventListener to IE8:
(function() {
function stopPropagation() {
this.cancelBubble = true;
}
function preventDefault() {
this.returnValue = false;
}
if (typeof Element !== "undefined" &&
typeof Element.prototype !== "undefined" &&
!Element.prototype.addEventListener) {
Element.prototype.addEventListener = function(eventName, handler, useCapture) {
if (useCapture) {
throw "Browser doesn't support capturing phase";
}
this.attachEvent("on" + eventName, function() {
var e = window.event;
e.stopPropagation = stopPropagation;
e.preventDefault = preventDefault;
handler.call(this, e);
});
};
}
})();
Live Example | Source

Generally, functions can be added to an object by attaching the function to the object
obj.addEventListener = function(/* args*/) { /* body */ }
or by attaching the function to the prototype of the object constuctor
EventTarget.prototype.addEventListener = function(/* args*/) { /* body */ }
With the former, the added function can be called on the particular object only, while the latter lets you call the function on all objects that where or will be created from that particular object constuctor.
However,
EventTargets are host objects and therefore it is implementation dependant whether functions can be added to such objects.
EventTargets are host objects and therefore it is implementation dependant whether EventTarget.prototype actually exists and has the same meaning as with native objects.
If an object adheres to the EventTarget interface, it most likely already has an addEventListener function.
The event listener attached with attachEvent has different arguments than the one added with addEventListener.
In the end, it is not feasable to try and make a browser with crappy DOM support more standards complient using JavaScript.

Related

How to redefine addEventListener to be attachEvent in older versions of IE

I have a plugin with many lines like this:
document.addEventListener('keypress', function(e) {
this.drop.addEventListener('click', function(e) {
I want to have a bit of javascript at the top which redefines addEventListener so it actually uses attachEvent in older browsers (I can use the navigator object). I don't want to have to do if statements for every line of code like above.
var addEvent = function (ele, event, func) {
if (ele.addEventListener) {
ele.addEventListener(event, func, false);
} else if (ele.attachEvent) {
ele.attachEvent('on' + event, func);
} else {
ele['on' + event] = func;
}
};
I think the best way is to add this event yourself.
This is the simplest implementation I can think of:
if (!Element.addEventListener)
Element.prototype.addEventListener = function(event,handler, placeholder) {
this.attachEvent('on'+event,handler);
}
After running this in the beginning of the page, you should be able to use addEventListener on your elements. I wrote should because you'll need more functions like this in order to use the same code on all browsers. Your best option is to use an existing code (like in polyfill) that will handle all of this.

How to catch a function call from class name in Javascript? [duplicate]

I have a page where some event listeners are attached to input boxes and select boxes. Is there a way to find out which event listeners are observing a particular DOM node and for what event?
Events are attached using:
Prototype's Event.observe;
DOM's addEventListener;
As element attribute element.onclick.
Chrome, Firefox, Vivaldi and Safari support getEventListeners(domElement) in their Developer Tools console.
For majority of the debugging purposes, this could be used.
Below is a very good reference to use it:
getEventListeners function
Highly voted tip from Clifford Fajardo from the comments:
getEventListeners($0) will get the event listeners for the element you have focused on in the Chrome dev tools.
If you just need to inspect what's happening on a page, you might try the Visual Event bookmarklet.
Update: Visual Event 2 available.
It depends on how the events are attached. For illustration presume we have the following click handler:
var handler = function() { alert('clicked!') };
We're going to attach it to our element using different methods, some which allow inspection and some that don't.
Method A) single event handler
element.onclick = handler;
// inspect
console.log(element.onclick); // "function() { alert('clicked!') }"
Method B) multiple event handlers
if(element.addEventListener) { // DOM standard
element.addEventListener('click', handler, false)
} else if(element.attachEvent) { // IE
element.attachEvent('onclick', handler)
}
// cannot inspect element to find handlers
Method C): jQuery
$(element).click(handler);
1.3.x
// inspect
var clickEvents = $(element).data("events").click;
jQuery.each(clickEvents, function(key, value) {
console.log(value) // "function() { alert('clicked!') }"
})
1.4.x (stores the handler inside an object)
// inspect
var clickEvents = $(element).data("events").click;
jQuery.each(clickEvents, function(key, handlerObj) {
console.log(handlerObj.handler) // "function() { alert('clicked!') }"
// also available: handlerObj.type, handlerObj.namespace
})
1.7+ (very nice)
Made using knowledge from this comment.
events = $._data(this, 'events');
for (type in events) {
events[type].forEach(function (event) {
console.log(event['handler']);
});
}
(See jQuery.fn.data and jQuery.data)
Method D): Prototype (messy)
$(element).observe('click', handler);
1.5.x
// inspect
Event.observers.each(function(item) {
if(item[0] == element) {
console.log(item[2]) // "function() { alert('clicked!') }"
}
})
1.6 to 1.6.0.3, inclusive (got very difficult here)
// inspect. "_eventId" is for < 1.6.0.3 while
// "_prototypeEventID" was introduced in 1.6.0.3
var clickEvents = Event.cache[element._eventId || (element._prototypeEventID || [])[0]].click;
clickEvents.each(function(wrapper){
console.log(wrapper.handler) // "function() { alert('clicked!') }"
})
1.6.1 (little better)
// inspect
var clickEvents = element.getStorage().get('prototype_event_registry').get('click');
clickEvents.each(function(wrapper){
console.log(wrapper.handler) // "function() { alert('clicked!') }"
})
When clicking the resulting output in the console (which shows the text of the function), the console will navigate directly to the line of the function's declaration in the relevant JS file.
WebKit Inspector in Chrome or Safari browsers now does this. It will display the event listeners for a DOM element when you select it in the Elements pane.
It is possible to list all event listeners in JavaScript: It's not that hard; you just have to hack the prototype's method of the HTML elements (before adding the listeners).
function reportIn(e){
var a = this.lastListenerInfo[this.lastListenerInfo.length-1];
console.log(a)
}
HTMLAnchorElement.prototype.realAddEventListener = HTMLAnchorElement.prototype.addEventListener;
HTMLAnchorElement.prototype.addEventListener = function(a,b,c){
this.realAddEventListener(a,reportIn,c);
this.realAddEventListener(a,b,c);
if(!this.lastListenerInfo){ this.lastListenerInfo = new Array()};
this.lastListenerInfo.push({a : a, b : b , c : c});
};
Now every anchor element (a) will have a lastListenerInfo property wich contains all of its listeners. And it even works for removing listeners with anonymous functions.
Use getEventListeners in Google Chrome:
getEventListeners(document.getElementByID('btnlogin'));
getEventListeners($('#btnlogin'));
(Rewriting the answer from this question since it's relevant here.)
When debugging, if you just want to see the events, I recommend either...
Visual Event
The Elements section of Chrome's Developer Tools: select an element and look for "Event Listeners" on the bottom right (similar in Firefox)
If you want to use the events in your code, and you are using jQuery before version 1.8, you can use:
$(selector).data("events")
to get the events. As of version 1.8, using .data("events") is discontinued (see this bug ticket). You can use:
$._data(element, "events")
Another example: Write all click events on a certain link to the console:
var $myLink = $('a.myClass');
console.log($._data($myLink[0], "events").click);
(see http://jsfiddle.net/HmsQC/ for a working example)
Unfortunately, using $._data this is not recommended except for debugging since it is an internal jQuery structure, and could change in future releases. Unfortunately I know of no other easy means of accessing the events.
1: Prototype.observe uses Element.addEventListener (see the source code)
2: You can override Element.addEventListener to remember the added listeners (handy property EventListenerList was removed from DOM3 spec proposal). Run this code before any event is attached:
(function() {
Element.prototype._addEventListener = Element.prototype.addEventListener;
Element.prototype.addEventListener = function(a,b,c) {
this._addEventListener(a,b,c);
if(!this.eventListenerList) this.eventListenerList = {};
if(!this.eventListenerList[a]) this.eventListenerList[a] = [];
this.eventListenerList[a].push(b);
};
})();
Read all the events by:
var clicks = someElement.eventListenerList.click;
if(clicks) clicks.forEach(function(f) {
alert("I listen to this function: "+f.toString());
});
And don't forget to override Element.removeEventListener to remove the event from the custom Element.eventListenerList.
3: the Element.onclick property needs special care here:
if(someElement.onclick)
alert("I also listen tho this: "+someElement.onclick.toString());
4: don't forget the Element.onclick content attribute: these are two different things:
someElement.onclick = someHandler; // IDL attribute
someElement.setAttribute("onclick","otherHandler(event)"); // content attribute
So you need to handle it, too:
var click = someElement.getAttribute("onclick");
if(click) alert("I even listen to this: "+click);
The Visual Event bookmarklet (mentioned in the most popular answer) only steals the custom library handler cache:
It turns out that there is no standard method provided by the W3C
recommended DOM interface to find out what event listeners are
attached to a particular element. While this may appear to be an
oversight, there was a proposal to include a property called
eventListenerList to the level 3 DOM specification, but was
unfortunately been removed in later drafts. As such we are forced to
looked at the individual Javascript libraries, which typically
maintain a cache of attached events (so they can later be removed and
perform other useful abstractions).
As such, in order for Visual Event to show events, it must be able to
parse the event information out of a Javascript library.
Element overriding may be questionable (i.e. because there are some DOM specific features like live collections, which can not be coded in JS), but it gives the eventListenerList support natively and it works in Chrome, Firefox and Opera (doesn't work in IE7).
Paste in console to get all eventListeners printed beside their HTML element
Array.from(document.querySelectorAll("*")).forEach(element => {
const events = getEventListeners(element)
if (Object.keys(events).length !== 0) {
console.log(element, events)
}
})
You could wrap the native DOM methods for managing event listeners by putting this at the top of your <head>:
<script>
(function(w){
var originalAdd = w.addEventListener;
w.addEventListener = function(){
// add your own stuff here to debug
return originalAdd.apply(this, arguments);
};
var originalRemove = w.removeEventListener;
w.removeEventListener = function(){
// add your own stuff here to debug
return originalRemove.apply(this, arguments);
};
})(window);
</script>
H/T #les2
The Firefox developer tools now does this. Events are shown by clicking the "ev" button on the right of each element's display, including jQuery and DOM events.
If you have Firebug, you can use console.dir(object or array) to print a nice tree in the console log of any JavaScript scalar, array, or object.
Try:
console.dir(clickEvents);
or
console.dir(window);
Fully working solution based on answer by Jan Turon - behaves like getEventListeners() from console:
(There is a little bug with duplicates. It doesn't break much anyway.)
(function() {
Element.prototype._addEventListener = Element.prototype.addEventListener;
Element.prototype.addEventListener = function(a,b,c) {
if(c==undefined)
c=false;
this._addEventListener(a,b,c);
if(!this.eventListenerList)
this.eventListenerList = {};
if(!this.eventListenerList[a])
this.eventListenerList[a] = [];
//this.removeEventListener(a,b,c); // TODO - handle duplicates..
this.eventListenerList[a].push({listener:b,useCapture:c});
};
Element.prototype.getEventListeners = function(a){
if(!this.eventListenerList)
this.eventListenerList = {};
if(a==undefined)
return this.eventListenerList;
return this.eventListenerList[a];
};
Element.prototype.clearEventListeners = function(a){
if(!this.eventListenerList)
this.eventListenerList = {};
if(a==undefined){
for(var x in (this.getEventListeners())) this.clearEventListeners(x);
return;
}
var el = this.getEventListeners(a);
if(el==undefined)
return;
for(var i = el.length - 1; i >= 0; --i) {
var ev = el[i];
this.removeEventListener(a, ev.listener, ev.useCapture);
}
};
Element.prototype._removeEventListener = Element.prototype.removeEventListener;
Element.prototype.removeEventListener = function(a,b,c) {
if(c==undefined)
c=false;
this._removeEventListener(a,b,c);
if(!this.eventListenerList)
this.eventListenerList = {};
if(!this.eventListenerList[a])
this.eventListenerList[a] = [];
// Find the event in the list
for(var i=0;i<this.eventListenerList[a].length;i++){
if(this.eventListenerList[a][i].listener==b, this.eventListenerList[a][i].useCapture==c){ // Hmm..
this.eventListenerList[a].splice(i, 1);
break;
}
}
if(this.eventListenerList[a].length==0)
delete this.eventListenerList[a];
};
})();
Usage:
someElement.getEventListeners([name]) - return list of event listeners, if name is set return array of listeners for that event
someElement.clearEventListeners([name]) - remove all event listeners, if name is set only remove listeners for that event
Update 2022:
In the Chrome Developer Tools, in the Elements panel, there is the Event Listeners tab, where you can see listeners for the element.
You can also unselect "Ancestors" so it only shows the listeners for that element
Opera 12 (not the latest Chrome Webkit engine based) Dragonfly has had this for a while and is obviously displayed in the DOM structure. In my opinion it is a superior debugger and is the only reason remaining why I still use the Opera 12 based version (there is no v13, v14 version and the v15 Webkit based lacks Dragonfly still)
Prototype 1.7.1 way
function get_element_registry(element) {
var cache = Event.cache;
if(element === window) return 0;
if(typeof element._prototypeUID === 'undefined') {
element._prototypeUID = Element.Storage.UID++;
}
var uid = element._prototypeUID;
if(!cache[uid]) cache[uid] = {element: element};
return cache[uid];
}
I am trying to do that in jQuery 2.1, and with the "$().click() -> $(element).data("events").click;" method it doesn't work.
I realized that only the $._data() functions works in my case :
$(document).ready(function(){
var node = $('body');
// Bind 3 events to body click
node.click(function(e) { alert('hello'); })
.click(function(e) { alert('bye'); })
.click(fun_1);
// Inspect the events of body
var events = $._data(node[0], "events").click;
var ev1 = events[0].handler // -> function(e) { alert('hello')
var ev2 = events[1].handler // -> function(e) { alert('bye')
var ev3 = events[2].handler // -> function fun_1()
$('body')
.append('<p> Event1 = ' + eval(ev1).toString() + '</p>')
.append('<p> Event2 = ' + eval(ev2).toString() + '</p>')
.append('<p> Event3 = ' + eval(ev3).toString() + '</p>');
});
function fun_1() {
var txt = 'text del missatge';
alert(txt);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
</body>
I was recently working with events and wanted to view/control all events in a page. Having looked at possible solutions, I've decided to go my own way and create a custom system to monitor events. So, I did three things.
First, I needed a container for all the event listeners in the page: that's theEventListeners object. It has three useful methods: add(), remove(), and get().
Next, I created an EventListener object to hold the necessary information for the event, i.e.: target, type, callback, options, useCapture, wantsUntrusted, and added a method remove() to remove the listener.
Lastly, I extended the native addEventListener() and removeEventListener() methods to make them work with the objects I've created (EventListener and EventListeners).
Usage:
var bodyClickEvent = document.body.addEventListener("click", function () {
console.log("body click");
});
// bodyClickEvent.remove();
addEventListener() creates an EventListener object, adds it to EventListeners and returns the EventListener object, so it can be removed later.
EventListeners.get() can be used to view the listeners in the page. It accepts an EventTarget or a string (event type).
// EventListeners.get(document.body);
// EventListeners.get("click");
Demo
Let's say we want to know every event listener in this current page. We can do that (assuming you're using a script manager extension, Tampermonkey in this case). Following script does this:
// ==UserScript==
// #name New Userscript
// #namespace http://tampermonkey.net/
// #version 0.1
// #description try to take over the world!
// #author You
// #include https://stackoverflow.com/*
// #grant none
// ==/UserScript==
(function() {
fetch("https://raw.githubusercontent.com/akinuri/js-lib/master/EventListener.js")
.then(function (response) {
return response.text();
})
.then(function (text) {
eval(text);
window.EventListeners = EventListeners;
});
})(window);
And when we list all the listeners, it says there are 299 event listeners. There "seems" to be some duplicates, but I don't know if they're really duplicates. Not every event type is duplicated, so all those "duplicates" might be an individual listener.
Code can be found at my repository. I didn't want to post it here because it's rather long.
Update: This doesn't seem to work with jQuery. When I examine the EventListener, I see that the callback is
function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}
I believe this belongs to jQuery, and is not the actual callback. jQuery stores the actual callback in the properties of the EventTarget:
$(document.body).click(function () {
console.log("jquery click");
});
To remove an event listener, the actual callback needs to be passed to the removeEventListener() method. So in order to make this work with jQuery, it needs further modification. I might fix that in the future.
There exists nice jQuery Events extension :
(topic source)
changing these functions will allow you to log the listeners added:
EventTarget.prototype.addEventListener
EventTarget.prototype.attachEvent
EventTarget.prototype.removeEventListener
EventTarget.prototype.detachEvent
read the rest of the listeners with
console.log(someElement.onclick);
console.log(someElement.getAttribute("onclick"));

How to reference the caller object ("this") using attachEvent

Using the method .attachEvent() in IE, how can I reference the caller object (the element that triggered the event) with this? In normal browsers, using .addEventListener, the var this points to the element, while in IE it points to the window object.
I need it to work with the following code:
var element = //the element, doesn't matter how it is obtained
element.addAnEvent = function(name, funct){
if(element.addEventListener) // Works in NORMAL browsers...
else if(element.attachEvent){
element.attachEvent("on"+name, funct);
//where the value of "this" in funct should point to "element"
}
}
I just made that code up, it's not exactly the same as my code, but if it works with it then it works with me!
From this quirksmode article with regard to attachEvent:
Events always bubble, no capturing possibility.
The event handling function is referenced, not copied, so the this keyword always refers to the window and is completely useless.
The result of these two weaknesses is that when an event bubbles up it is impossible to know which HTML element currently handles the event. I explain this problem more fully on the Event order page.
Since the Microsoft event adding model is only supported by Explorer 5 and higher on Windows, it cannot be used for cross–browser scripts. But even for Explorer–on–Windows only applications it’s best not to use it, since the bubbling problem can be quite nasty in complex applications.
I haven't tested it, but a possible workaround may be to wrap the handler in an anonymous function that calls your handler via funct.call().
else if(element.attachEvent){
element.attachEvent("on"+name, function(){ funct.call( element ) });
}
My apologies for the untested solution. I don't like doing that, but can't easily get to IE right now.
If you're in IE, you can get the "caller" object, as you call it, by accessing window.event.srcElement within the event handler function. This object is normally referred to as the event target or source.
var funct = function(event) {
if ( !event ) {
event = window.event;
}
var callerElement = event.target || event.srcElement;
// Do stuff
};
This code is untested, but should set you off in the right direction.
Bind it. Well, you can't use Function.prototype.bind that gets added in javascript 1.8.5, but you can use closure and Function.prototype.apply.
var element = //the element, doesn't matter how it is obtained
element.addAnEvent = function(name, funct){
if(element.addEventListener) // Works in NORMAL browsers...
//...
else if(element.attachEvent){
element.attachEvent("on"+name, function() {
//call funct with 'this' == 'element'
return funct.apply(element, arguments);
});
}
}
I think it would be better to extend the Element object , through the prototype chain, instead of adding your method to each element you want to add events to (works with all browsers)..
Element.prototype.addAnEvent = function(name, funct){
if(this.addEventListener) // Works in NORMAL browsers...
{
this.addEventListener(name,funct, false);
}
else if(this.attachEvent){
var _this = this;
this.attachEvent("on"+name, function(){funct.apply(_this);});
//where the value of "this" in funct should point to "element"
}
};
This way it will work for all your current and future elements (and you only have to run it once).

JavaScript add events cross-browser function implementation: use attachEvent/addEventListener vs inline events

In order to add events we could use this simple first solution:
function AddEvent(html_element, event_name, event_function)
{
if(html_element.attachEvent) //Internet Explorer
html_element.attachEvent("on" + event_name, function() {event_function.call(html_element);});
else if(html_element.addEventListener) //Firefox & company
html_element.addEventListener(event_name, event_function, false); //don't need the 'call' trick because in FF everything already works in the right way
}
or this second solution (that adds inline events):
function AddEvent(html_element, event_name, event_function)
{
var old_event = html_element['on' + event_name];
if(typeof old_event !== 'function')
html_element['on' + event_name] = function() { event_function.call(html_element); };
else
html_element['on' + event_name] = function() { old_event(); event_function.call(html_element); };
}
These are both cross-browsers and can be used in this way:
AddEvent(document.getElementById('some_div_id'), 'click', function()
{
alert(this.tagName); //shows 'DIV'
});
Since I have the feeling attachEvent/addEventListener are used more around in events handling implementations, I'm wondering:
Are there any disadvantages/drawbacks against using the second solution that I might better be aware of?
I can see two, but I'm interested in more (if any):
the second solution screws up innerHTML of elements by adding events inline
Using second solution I can easily remove all functions associated with a certain event type (html_element['on' + event_name] = null), but I can not use detachEvent/removeEventListener to remove exactly a specific function.
Any answers like: "use jQuery" or any other framework are pointless!
With the 2nd solution, you have to manually call the previous functions, making it hard to remove specific listeners (which, to me, sounds like something you'd rather want than clearing all listeners), while on the first solution, you can only clear them all at the same time, unless you want to emulate the first functionality.
Personally, I always use the first solution, because it has the advantage of not having to worry about clearing possible other event listeners.
The mozilla wiki also lists the advantages that the first solution works on any DOM element, not just HTML elements, and that it allows finer grained control over the phase when the listener gets activated (capturing vs. bubbling) with the third argument.
i would use both codes like this
function addEvent(html_element, event_name, event_function) {
if (html_element.addEventListener) { // Modern
html_element.addEventListener(event_name, event_function, false);
} else if (html_element.attachEvent) { // Internet Explorer
html_element.attachEvent("on" + event_name, event_function);
} else { // others
html_element["on" + event_name] = event_function;
}
};

How to Fire Personal Event in Javascript

I can't fire personal events using Javascript in IE. In Firefox work great.
My code is:
var evento;
if(document.createEventObject)
{
evento = document.createEventObject();
document.fireEvent('eventoPersonal', evento);
}
//FF
else
{
evento = document.createEvent('Events');
evento.initEvent('eventoPersonal',true,false);
document.dispatchEvent(evento);
}
But when try to execute document.fireEvent('eventoPersonal', evento); in IE, it doesn't work. How can I fire NO custom events in IE?
In Internet Explorer I get the error: "Invalid arguments" in the line where execute document.fireEvent('eventoPersonal', evento);
Dean Edward's describes how to fire cutsom events in IE
http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/
Its near the bottom of the article
var currentHandler;
if (document.addEventListener) {
// We've seen this code already
} else if (document.attachEvent) { // MSIE
document.documentElement.fakeEvents = 0; // an expando property
document.documentElement.attachEvent("onpropertychange", function(event) {
if (event.propertyName == "fakeEvents") {
// execute the callback
currentHandler();
}
});
dispatchFakeEvent = function(handler) {
// fire the propertychange event
document.documentElement.fakeEvents++;
};
}
I think the answer is - in IE you can not fire events that are not on this list:
MSDN - DHTML Events
From what I can gather, frameworks store a registry of the "custom" event names and you must use their implementation specific trigger and handle functions for custom events. For example, prototype uses the ondatavailable event to pass through their custom events behind the scenes.
You may want to consider using a library to abstract this. Both prototype an jquery will handle this for you. Jquery is especially good at allowing you to create an event with very simple code.
Jquery's documentation is available here:
http://docs.jquery.com/Events
In IE11 document.dispatchEvent still doesn't work, but now attachEvent is missing too, so the other solution is not going to work either. However, I came up with one even uglier. :) It involves replacing the addEventListener method and goes on like this:
var oldEventListener = document.addEventListener;
document.addEventListener = function (event, func, capture) {
if (event == "MyPreciousCustomEvent") {
document.MyPreciousCustomEvent = func;
}
oldEventListener.call(document, event, func, capture);
};
...
$(function () {
try {
document.MyPreciousCustomEvent("MyPreciousCustomEvent", {});
} catch (e) {}
});
Hope this helps someone.
As I read the relevant MSDN article page on the createEventObject method, it appears as though it isn't used for creating custom event - it is used for creating custom objects that can be passed to already existing events.
Description:
Generates an event object to pass event context information when you use the fireEvent method.
http://msdn.microsoft.com/en-us/library/ms536390%28VS.85%29.aspx
Update: You are getting the "invalid arguments" error because 'eventoPersonal' is not an acceptable event to fire.
Yeah referring to #Don Albrecht, you can use jquery trigger() method more on http://api.jquery.com/trigger/

Categories