views:

499

answers:

9

Hi all,

Does anybody know how to add an event in the head of the queue for concrete event type?

I.e. I have already defined onclick event. A want to add additional call back function, that will be invoked BEFORE already defined callback.

Thanks in advance

A: 

addEventListener lets you add another event. Note that in IE you will have to use attachEvent.

This will not let you define the order of the events - appearently you can't predict the order the events will be fired in. So if you really want a predictable event queue for an event, you will have to implement it yourself.

Kristian J.
A: 

Hello,

You can stop the default action of an event with preventDefault() or stop the propagation of nested event with stopPropagation() to let only your specific event fire.

But pause or delay an event natively without using setTimeout(), stopping, saving his state and re-firing later in the queue is impossible.

belaz
A: 

Are there any libraries which provide the functionality of ordered event callbacks invocation?

2belaz: preventDefault could be useful for me. thanks

glaz666
Please post responses to other answers as comments inside the corresponding answers and not as separate answers.
Ates Goral
+1  A: 

If you use attachEvent for IE you cannot guarantee the order in which events are fired. See http://msdn.microsoft.com/en-us/library/ms536343(VS.85).aspx

If you attach multiple functions to the same event on the same object, the functions are called in random order, immediately after the object's event handler is called.

(I actually have seen that events are called in reverse order, not random). Anyway, libraries generally tend to use attachEvent deep down, so you're stuck with the same problem.

Having said that, if you can inspect a node for it's 'click' handlers (eg you have an "onclick" attribute setup on your node in your markup), then you can put "yours" ahead of "theirs":

var nodes = document.getElementsByTagName('*'); // collect your nodes however
for(var i=0; i < nodes.length; i++) {
    var node = nodes[i];
    if(!node.onclick)
        continue;

    // At this point we have a node with an "onclick" attr.
    // Hijack onclick to do something else first.
    var original = node.onclick;
    node.onclick = function() {
        doSomethingElse();
        return original.apply(this, arguments);
    }
}

See this answer for how to inspect the a node's events in other libraries (if you are using one). You may be able to use it to doSomethingElse() with those libraries too.

Crescent Fresh
A: 

2crescentfresh: Thanks. It is indeed interesting solution.

I want to implement kind of trigger, that will either permit rest of handlers or totally discard any other activities. But I want make it flexible.

That means no matter how the handlers are attached to the element - inline (onclick='bla-bla'), traditionally (element.onclick = function(){}), according to W3C standards (usind addEventListener and etc.), or using frameworks helpers, the trigger must do its work.

So if I combine your solution and belaz's one (with event.preventDefault()), I wonder will it work for all the situations I have described?

glaz666
A: 

I don't fully understand the question, but i'll try to respond.

You can simply stop an event listeners by simply load this sample function with correct params (see removeEventListener()) :

   function removeEvent(obj,type,fn){
  if(obj.removeEventListener) obj.removeEventListener(type,fn,false);
  else if(obj.detachEvent){
    obj.detachEvent("on"+type,obj[type+fn]);
    obj[type+fn]=null;
    obj["e"+type+fn]=null;
  }
}

Also, you can fire à setTimeout within the event that kill other listeners and re-enable listener one by one, externally or with an other setTimeout.

Sorry if it doesnt help.

EDIT :

a library to debug events, maybe useful.

http://developer.yahoo.com/yui/event/

belaz
A: 

2belaz: thanks for your concern. I will give an exact example of what i'm trying to do:

<script>
 //onload 
$( 
function() {
  var handler2 = function(){ alert( "2" ); }
  $('#divId').click( handler2() );
});

//here should be trigger implementation
$(
function() {
  $('#divId').each(
    function() {
      var original = this.onclick;
      this.onclick = function( e ){
        if ( false ) { //some condition to be checked. Lets fail it always for ex,
          /* __HERE__ cancel all events */
        }  
        return original ? original.apply(this, arguments) : true;
      }
    });
} ); 

function handler1(){
  alert("1");
}
</script>
//...
<div id='myDiv' onclick='handler1(); return false;' > clickable </div>
//...

So in the //HERE cancel all events

should be function that will cause all events to be canceled so that neither hander1() nor handler2() are not invoked

Any ideas?

glaz666
A: 

Are you working with jquery framework ? I'm currently working with extjs and i found a class you can use or copy

Lets see on http://extjs.com/deploy/dev/docs/ Ext > EventManager > removeAll()

removeAll( String/HTMLElement el ) : void Removes all event handers from an element. Typically you will use Ext.Element.removeAllListeners directly on an Element in favor of calling this version. Parameters: el : String/HTMLElement The id or html element from which to remove the event Returns: void

I think You can set the tag body as HTMLElement to shut down all events. (not tested sorry)

Download here http://extjs.com/products/extjs/build/ > select jquery adapter if you are working with jquery > extcore will suffice (it contain EventManager.js ).

On the other way, like crescentfresh (answer n°4), i made this sample code to apply to all node events :

var nodes = document.getElementsByTagName('*'); // collect your nodes however
for(var i=0; i < nodes.length; i++) {
     var node = nodes[i];
     Ext.EventManager.removeAll(node);
    }
}

Please let me know if you have trouble using extjs i can help, and vote for me if my answer is useful.

belaz
+1  A: 

Super. That made me look into jquery doc and I've found that combining crescentfresh's solution with jQuery's unbing() method (anal of Extjs.removeAll() ) will solve my issue.

So, at the end I have this:

this.onclick = function( e ) 
        if ( /*trigger clause*/ true ) { 
          //cancel all events
          $(this).unbind();
          return false;
        } else {
          //continue processing  
          return original ? original.apply(this, arguments) : true;
        }
      }

Thanks for advices guys!

PS What the jerks have made this awful reply editor??! It's a headache to paste some code here.

PPS Unfortunatelly I can't vote for two replys and I can't raise useful mark for your reply due to lack of reputation and I can't mark more than one answer acceptable. So, please forgive me. Stupid forum engine, but really cool people here

glaz666