in javascript, manually controlling order of event listeners
Assuming that FORM contains INPUT, have the following listeners:
javascript
function formFirst(e) { ... }
function formLast(e) { ... }
function inputFirst(e) { ... }
function inputLast(e) { ... }
function middle(e) { ... }
document.getElementById('form').addEventListener('change',formFirst,true);
document.getElementById('form').addEventListener('change',formLast,false);
document.getElementById('input').addEventListener('change',inputFirst,true);
document.getElementById('input').addEventListener('change',inputLast,false);
desired order of firing
formFirst() // normal - outer element, useCapture = true
inputFirst() // normal - triggering element, declared first
middle() // -- how to do this?
inputLast() // normal - triggering element, declared second
formLast() // normal - outer element, useCapture = false
nature of problem and attempted solutions
Own code at FORM level, formFirst
, formLast
and middle
, but have no access to INPUT code, inputFirst
and inputLast
- although could add own listeners on the INPUT.
Attempt 1 modify formFirst()
to create and dispatch a new change Event
(would be ignored within formFirst
) that would call inputFirst()
, but have no way of stopping propagation to prevent inputLast()
being called subsequently.
Attempt 2 add middle
added as listener to INPUT, but cannot guarantee firing order of two listeners of same type and same useCapture.
Premise of Attempt 2 is incorrect - firing order is determined by declaration order within the target Element.
Here are the rules
non-target Element triggers with useCapture=false
, starting at the outermost Element and working toward the target Element
a) if more than one useCapture=true
triggers for same element, then order of declaration.
at target Element, order of declaration, regardless of useCapture
non-target Element triggers with useCapture=false
, starting at the innermost Element and working away from the target Element
a) if more than one useCapture=false
triggers for same Element, then order of declaration.
I think that this answers just your question. feel free to commentcontact me for more info.
----- edit ------
OK, I just played with it a little as promised, and I found a very simple solution:
<script type="text/javascript">
function formFirst(e) { alert(1); }
function formLast(e) { alert(5); }
function inputFirst(e) { alert(2); }
function inputLast(e) { alert(4); }
function middle(e) { alert(3); }
function init(){
document.getElementById('form').addEventListener('change',formFirst,true);
document.getElementById('form').addEventListener('change',formLast,false);
document.getElementById('input').addEventListener('change',inputFirst,true);
document.getElementById('input').addEventListener('change',middle,true);
/*** alternative to last tow lines
document.getElementById('input').addEventListener('change',function(){inputFirst();middle();},true);
**/
document.getElementById('input').addEventListener('change',inputLast,false);
}
</script>
<body onload="init();">
<form id="form">
<input type="text" id="input" /> <br />
</form>
</body>
notice:
An alternative is writing the event handling on your own. here is an example for that. relaying on this article.
<script type="text/javascript">
function formFirst(e) { alert(1); }
function formLast(e) { alert(5); }
function inputFirst(e) { alert(2); }
function inputLast(e) { alert(4); }
function middle(e) { alert(3); }
function init(){
//create event
myHandler = new Event();
//add handler
myHandler.addHandler(formFirst);
myHandler.addHandler(inputFirst);
myHandler.addHandler(middle);
myHandler.addHandler(inputLast);
myHandler.addHandler(formLast);
//regiser one listener on some object
document.getElementById('input').addEventListener('change',function(){myHandler.execute();},true);
}
function Event(){
this.eventHandlers = new Array();
}
Event.prototype.addHandler = function(eventHandler){
this.eventHandlers.push(eventHandler);
}
Event.prototype.execute = function(){
for(var i = 0; i < this.eventHandlers.length; i++){
this.eventHandlers[i]();
}
}
</script>
<body onload="init();">
<form id="form">
<input type="text" id="input" /> <br />
</form>
</body>