javascriptinternet-explorerdom-eventsmutation-observersmutation-events

removeEventListener not working in IE10, works in Chrome


I am trying to create a mini library using MutationObserver to detect changes in DOM but also to fallback to basic Mutation Events in older browsers. So far so good, it works properly in Chrome and Firefox and I tested the fallback in these browsers too - everything worked but when I tested it IE 10 it behaves differently (how unexpected...)

In this library you can simply call:

domWatch(someDOMNode, callback)

callback gets one parameter - an observer with disconnect and observe methods so you can stop watching the node while you do some changes to it and then start watching again.

domWatch(document.querySelector('div'), function (obs) {
    setTimeout(function () {
        obs.disconnect();
        $(obs.node).append('a');
        obs.observe();
    }, 1200);
});

In the fallback I use mutation events and add/remove event listeners. I think the problem is that in IE the event is not really removed is, it gets stuck in infinite loop (my code is in setTimeout so it will not crash your browser). For some reason it probably thinks that this.realCallback are different functions?

FallbackObserver.prototype.observe = function () {
    this.node.addEventListener("DOMSubtreeModified", this.realCallback, true);
}

FallbackObserver.prototype.disconnect = function () {
    this.node.removeEventListener("DOMSubtreeModified", this.realCallback, true);
}

I created a mini fiddle only with the problematic code, try to run it in Chrome and then in IE10: http://jsfiddle.net/Hb45w/2/

(Full library Fiddle: http://jsfiddle.net/x6W3p/)


Solution

  • Managed to solve it:

    All browsers were correctly removing and adding events - the problem was something else.

    The actual problem with IE is probably some aspect of rendering engine - I disconnected the event handler, did the change and started observing again:

        obs.disconnect();
        $(obs.node).append('a');
        obs.observe();
    

    The problem was that the event was obviously attached back before IE finished the rendering (probably some asynchronous execution).

    Changing

    FallbackObserver.prototype.observe = function () {
        this.node.addEventListener("DOMSubtreeModified", this.realCallback, true);
    }
    

    to

    FallbackObserver.prototype.observe = function () {
        var that = this;
        setTimeout(function () {
           that.node.addEventListener("DOMSubtreeModified", that.realCallback, true);
        }, 0);
    }
    

    did the trick. But I am not sure whether it will work if some more complex DOM changes will be performed.