Consider this button:
<button id="the_button" onclick="RunOnClick();">Click</button>
This button has an inline onclick
event handler. The contents of the RunOnClick
function don't matter for this question.
If I ALSO attach another click event listener like so:
var btn = document.getElementById('the_button');
btn.addEventListener("click", function(){
// Do Something
});
The handler registered with addEventListener
always seems to run after the inline onclick=""
one.
Can I always rely on the single inline onclick
handler to fire first and the addEventListener
handler to fire later?
Is this a fluke? Or is it actually designed that way and part of one of the ECMAScript specifications?
This feels like a back to the basics quality of question, but I don't know the answer.
The answer is, yes, this is actually covered in the specification but not the ECMAScript spec per se, which only strictly deals with ECMAScript independent of implementation.
Firstly, the ordering of DOM events. I refer you to this relevent SO question.
Are event handlers in JavaScript called in order?
As this states, previously it was unspecifed but as of the DOM level 3 spec it does specifically state they should be executed in the order that they are registered.
But what about inline event handlers defined like in your example?
For this we can turn to the HTML 5 spec which says:
An event handler content attribute is a content attribute for a specific event handler. The name of the content attribute is the same as the name of the event handler.
[...]
When an event handler
H
of an element or objectT
implementing the EventTarget interface is first set to a non-null value, the user agent must append an event listener to the list of event listeners associated withT
with type set to the event handler event type corresponding toH
and callback set to the event handler processing algorithm defined below.
Unpacking this and the subsequent notes a bit the key things to take away here are:
onclick
attribute) will cause an event listener to be added to the list referred to earlier in the DOM spec.onclick
attribute but an internal event handler processing algorithm for evaluating the attribute and executing the appropriate callback.This might be a bit confusing. It might help to read and digest the notes on the spec yourself, but I will also try to cover the key implications below.
Firstly, yes, the behaviour you see is effectively defined by the spec as a logical result of what the spec tells us. When a document is being parsed and encounters an inline event handler attribute then this internal algorithm is added to the list of event listeners immediately. According to the spec then this will mean that the first event listener will be the one corresponding to your event handler attribute. Since this has to have been set before any calls to addEventListener
since it wouldn't be possible to call addEventListener
on a element that didn't exist then. In these circumstances it will always execute first.
The interesting stuff happens when we start messing with the inline attribute after the initial parsing. Here's an example from the HTML5 spec itself that appears right after the bit I quoted above:
EXAMPLE 8
This example demonstrates the order in which event listeners are invoked. If the button in this example is clicked by the user, the page will show four alerts, with the text "ONE", "TWO", "THREE", and "FOUR" respectively.
<button id='test'>Start Demo</button>
<script>
var button = document.getElementById('test');
button.addEventListener('click', function () { alert('ONE') }, false);
button.setAttribute('onclick', "alert('NOT CALLED')"); // event handler listener is registered here
button.addEventListener('click', function () { alert('THREE') }, false);
button.onclick = function () { alert('TWO'); };
button.addEventListener('click', function () { alert('FOUR') }, false);
</script>
As we can see then the initial value of the onclick attribute is overriden, but the new onclick handler still executes between the first and the second listener set with addEventListener
. The reason for this is that the inline event handler will effectively always be in the list of listeners at the same point it was when it was first added to the element. This is because technically, as stated earlier, the actual event listener is not the callback we have specified in the attribute content, but an internal algorithm that takes the attribute contents as it's input.
I have created a JSFiddle to test this is the case and I can confirm this is the behaviour I see in both Firefox and Chrome.
So to summarise, in practical terms:
setAttribute
, then they will respect the order in which they were added respective to earlier and later calls to addEventListener
.Hope that clears things up!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With