I've been using Prototype for a while now and I'm really surprised that it took me this long to learn about Event.stop. Event.stop does just what it sounds like it does, namely, stops an event from firing. Let's look at some code that any person who has ever done Javascript work has written:

<a href="/content.html" onclick="Element.show('MyDiv');return false;">Click</a>

Clicking the link will cause the div with id 'MyDiv' to appear and the return false prevents the link from being followed. You might use this to, e.g., create collapsable menus. Soon, however, you might need to do something complicated and are forced to upgrade your code.

link.onclick = function() {
    Element.show('MyDiv');
    for () {
        // something complicated
    }
    return false;
}

Ok, so now, at least, there's no Javascript right inline with your HTML and you have more control over what exactly happens when the link is clicked. Super. What happens if we want to call two or more funcitons in a single click, say, f1, f2, and f3? The "stupid" solution would be

link.onclick = function() {
    f1();
    f2();
    f3();
    return false;
}

Why is this "stupid?" Well, for one, we're going to be writing a lot of little wrapper functions if we go down this route. What if on one page you want to call just f1 and f2 but not f3, and on another page want to call all three? Do you write two wrapper functions?

Second, you need to have all functions available at the time you set onclick. This means the 'onclick' handler might be set somewhere far, far away from the actual link itself, making for less maintainable code. Third, if the functions are logically distinct it only make sense to keep them logically distinct. Prototype solves this sanely by offering event listeners.

Event.observe(link, 'click', f1);
Event.observe(link, 'click', f2);
Event.observe(link, 'click', f3);

Now when the link is clicked all three of the functions will fire but the three functions are no longer so tightly coupled. But now we have a new problem — when we click on a link we now actually go to the URL. Oops. Returning false in one of the called functions does no good. One solution would be


Event.observe(link, 'click', f1);
Event.observe(link, 'click', f2);
Event.observe(link, 'click', f3);
link.onclick = function() { return false; }

This works but is, in my opinion, ugly and inconsistent. Enter Event.stop!

Event.observe(link, 'click', function(e) {
    Element.show('MyDiv');
    for () {
        //complicated stuff
    }
   
    Event.stop(e);
});

Problem solved. Bingo bango.

4 Comments

  1. mitcho May 17th, 2007 / 11:07 pm

    Zappa dappa! Now we’re in fat city!

  2. Eimantas May 17th, 2007 / 11:35 pm

    You should use span instead of a tag. it supports onClick and does not need any returning. next thing - if you use link for event capturing - what happens if use has turned off js support? in this case you should provide user with link to a page with div you’re trying to show (this will add functionality for a user to open that div in a new window with middle-click)

  3. Jesse May 17th, 2007 / 11:43 pm

    In the example code above I’ve intended “link” to be a reference to the DOM object, so that the “href” attribute can still point to wherever. I guess I used “#” in the only non-JS example. I’ll change that.

    As for using spans, well, that presents two issues: one, it’s not really semantic; two, it makes styling hard. If a span is really just a “link to nowhere” then it should be marked up as a link, not as the semantically null span tag. And styling would become a pain in the butt. For all such link/spans would I add a “link” class and then duplicate all my link-specific styling rules?

  4. Chris April 29th, 2008 / 11:58 am

    The one rather unfortunate part about Event.stop is that it only cancels propagation of the event to subsequent DOM elements, but not to other registered listeners. So if I register two click listeners and I happen to know in which order they fire, if I cancel the event via Event.stop, the subsequent handler will still be notified. Ultimately this weakness has nothing to do with prototype, but it’s still a bummer.

Leave a Reply