Firing Javascript Events (like onchange)

by @jehiah on 2008-01-23 15:20
Filed under: All, Firefox, IE, Javascript, Programming, Web

I thought I would throw this post out there because it's an easy thing to miss as a beginner (and yes it's almost as easy to forget once you are more advanced and grasp it).

The problem is that if you have a handle to an object you would normally expect to run an event this way: (I will use the onchange event as an example)

[html]
<input type="text" onchange="alert('i was clicked')" id="test">
<script>
document.getElementById("test").onchange()
</script>
[/html]

Which worked fine didn't it? But there are other ways functions can get attached. Often times you set functions programatically.

[html]
<input type="text" id="test">
<script>
obj = document.getElementById("test");
obj.onchange = function(){alert('hi');};
obj.onchange();
</script>
[/html]

That method of course only lets you set one function as the event handler, as setting another will just overwrite it. This is why libraries like prototype have really useful shorthand notation (Event.observe) for using the proper method of binding events addEventListener and addEvent.

[html]
<input type="text" id="test">
<script>
obj = document.getElementById("test");
Event.observe(obj,'change',function(){alert('hi');});
obj.onchange();
</script>
[/html]

Whoa the call to onchange doesn't work anymore! If you were to change values in the field through the browser it will still get called just fine. Why?

The problem is that the onchange event is not getting called properly. You can't call events just like you would normal functions, because there may be more than one function listening for an event, and they can get set in several different ways (like I showed above).

Unfortunately, the 'right way' to fire an event is not so easy because you have to do it differently in Internet Explorer (using document.createEventObject) and Firefox (using document.createEvent("HTMLEvents"))

[js]
function fireEvent(element,event){
    if (document.createEventObject){
    // dispatch for IE
    var evt = document.createEventObject();
    return element.fireEvent('on'+event,evt)
    }
    else{
    // dispatch for firefox + others
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent(event, true, true ); // event type,bubbling,cancelable
    return !element.dispatchEvent(evt);
    }
}
[/js]

Now we can finally use this new method to run our event.

[html]
<input type="text" id="test">
<script>
obj = document.getElementById("test");
Event.observe(obj,'change',function(){alert('hi');});
fireEvent(obj,'change');
</script>
[/html]

My fireEvent function is not perfect, I am just using it to point out the problem and how to work around it. prototype.js version 1.6 incorporates a more complete solution for this called Event.fire (at least I hope it's more complete). Update: as Jason points out, the Event.fire method in prototype 1.6 doesn't implement firing events like onchange. I should know to test things first before writing about them. <!-- It would be used like this:

[js]
obj= document.getElementById('test')
Event.fire(obj,'change');
// or
Event.fire('test','change');
// or even
obj.fire('change');
[/js]

-->

Hopefully, that helps explain why sometimes you can't fire an event using the shorthand notation obj.onchange().

All the examples on this page can be tested on the example page

Subscribe via RSS ı Email
© 2014 - Jehiah Czebotar