5

I understand the proper way to handle event.stopPropagation for IE is

if(event.stopPropagation) {
    event.stopPropagation();
} else {
    event.returnValue = false;
}

But is it possible to prototype Event so that I don't have to do the check each and everytime I use stopPropagation?

This question seemed helpful: JavaScript Event prototype in IE8 however I don't quite understand the accepted answer and how it is a prototype that can essentially be set and forget.

Community
  • 1
  • 1
ryandlf
  • 27,155
  • 37
  • 106
  • 162

3 Answers3

7

Probably this:

Event = Event || window.Event;
Event.prototype.stopPropagation = Event.prototype.stopPropagation || function() {
    this.cancelBubble = true;
}

returnValue = false is an analogue for preventDefault:

Event.prototype.preventDefault = Event.prototype.preventDefault || function () {
    this.returnValue = false;
}
mishik
  • 9,973
  • 9
  • 45
  • 67
  • In the other question I posted a link to the poster mentions this method but accepted a different answer. He mentions it not working via jsFiddle. That is why I was concerned with this method... – ryandlf Jun 14 '13 at 06:29
6

If you're doing your own event handling in plain javascript, then you probably already have a cross browser routine for setting event handlers. You can put the abstraction in that function. Here's one that I use that mimics the jQuery functionality (if the event handler returns false, then both stopPropagation() and preventDefault() are triggered. You can obviously modify it however you want it to behave:

// refined add event cross browser
function addEvent(elem, event, fn) {
    // allow the passing of an element id string instead of the DOM elem
    if (typeof elem === "string") {
        elem = document.getElementById(elem);
    }

    function listenHandler(e) {
        var ret = fn.apply(this, arguments);
        if (ret === false) {
            e.stopPropagation();
            e.preventDefault();
        }
        return(ret);
    }

    function attachHandler() {
        // normalize the target of the event
        window.event.target = window.event.srcElement;
        // make sure the event is passed to the fn also so that works the same too
        // set the this pointer same as addEventListener when fn is called
        var ret = fn.call(elem, window.event);   
        // support an optional return false to be cancel propagation and prevent default handling
        // like jQuery does
        if (ret === false) {
            window.event.returnValue = false;
            window.event.cancelBubble = true;
        }
        return(ret);
    }

    if (elem.addEventListener) {
        elem.addEventListener(event, listenHandler, false);
    } else {
        elem.attachEvent("on" + event, attachHandler);
    }
}

Or, you can just make a utility function like this:

function stopPropagation(e) {
    if(e.stopPropagation) {
        e.stopPropagation();
    } else {
        e.returnValue = false;
    }    
}

And just call that function instead of operating on the event in each function.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Just so i'm clear...when you use fn.call isn't that actually firing the function that was passed into the event handler? I'm not sure I understand how or why it would return false? What if the event handler does not happen to use event.stopPropagation? – ryandlf Jun 14 '13 at 06:47
  • And just one more thing. I've never seen return use brackets. Out of curiosity, is that any different than return ret;? – ryandlf Jun 14 '13 at 06:50
  • @ryandlf - yes fn.call is calling your custom event handler function (the one that was passed in with `addEvent()` to install the event handler. If you want to `stopPropagation()` of a particular event, then you `return false` in your event handler function. If not, you don't. It's up to the event handler function to decide if it wants to stop propagation or not. This is the model that jQuery uses. – jfriend00 Jun 14 '13 at 06:51
  • @ryandlf `return false` is no different than `return(false)`. There are cases with multiline statements where the parens are required to make sure the JS interpreter gets it right. The parens are not normally needed with the `return` statement. – jfriend00 Jun 14 '13 at 06:52
  • So for each event handler i've already written I have to go back and remove the e.stopPropagation() and instead use return false and it will call both stopProp and preventDefault? In other words its necessary to explicitly not call those functions within the event handler function or it will fail cross browser? – ryandlf Jun 14 '13 at 07:02
  • @ryandlf - `e.stopPropagation()` will fail and halt execution if the `stopPropagation` property doesn't exist on the event object. You will need to remove them if you want your code to work in browses that don't have the `e.stopPropagation()` method - which I thought was the whole point of your question. You will also have to register all your event handlers with this new event function. – jfriend00 Jun 14 '13 at 07:05
  • Makes sense...i'm working with production code and have a lot of handlers already written with my custom implementation is why I wanted to be clear. Not a huge deal to go back and edit the functions but I just wanted to be sure before I started the task. Thanks for the help. – ryandlf Jun 14 '13 at 07:08
-1

We can use this alone: event.cancelBubble = true.

Tested working in all browsers.

Matthew Strawbridge
  • 19,940
  • 10
  • 72
  • 93