diff --git a/lib/utils.js b/lib/utils.js index 41754c071..228c2f9b9 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -110,7 +110,7 @@ function patchEventTargetMethods(obj) { })(handler); } else { fn = handler; - } + } handler[originalFnKey] = fn; handler[boundFnsKey] = handler[boundFnsKey] || {}; @@ -118,7 +118,10 @@ function patchEventTargetMethods(obj) { arguments[1] = handler[boundFnsKey][eventType]; } - var target = isWebWorker() && !this ? self : this; + // - Inside a Web Worker, `this` is undefined, the context is `global` (= `self`) + // - When `addEventListener` is called on the global context in strict mode, `this` is undefined + // see https://github.com/angular/zone.js/issues/190 + var target = this || global; return global.zone.addEventListener.apply(target, arguments); }; @@ -129,11 +132,15 @@ function patchEventTargetMethods(obj) { var eventType = eventName + (useCapturing ? '$capturing' : '$bubbling'); if (handler[boundFnsKey] && handler[boundFnsKey][eventType]) { var _bound = handler[boundFnsKey]; - arguments[1] = _bound[eventType]; delete _bound[eventType]; } - var target = isWebWorker() && !this ? self : this; + + // - Inside a Web Worker, `this` is undefined, the context is `global` + // - When `addEventListener` is called on the global context in strict mode, `this` is undefined + // see https://github.com/angular/zone.js/issues/190 + var target = this || global; + var result = global.zone.removeEventListener.apply(target, arguments); global.zone.dequeueTask(handler[originalFnKey]); return result; diff --git a/test/patch/element.spec.js b/test/patch/element.spec.js index bc2e92c90..b90d172af 100644 --- a/test/patch/element.spec.js +++ b/test/patch/element.spec.js @@ -14,6 +14,35 @@ describe('element', function () { document.body.removeChild(button); }); + // https://github.com/angular/zone.js/issues/190 + it('should work when addEventListener / removeEventListener are called in the global context', function () { + var clickEvent = document.createEvent('Event'); + var callCount = 0; + + clickEvent.initEvent('click', true, true); + + var listener = function (event) { + callCount++; + expect(zone).toBeDirectChildOf(testZone); + expect(event).toBe(clickEvent) + }; + + testZone.run(function() { + // `this` would be null inside the method when `addEventListener` is called from strict mode + // it would be `window`: + // - when called from non strict-mode, + // - when `window.addEventListener` is called explicitely. + addEventListener('click', listener); + }); + + button.dispatchEvent(clickEvent); + expect(callCount).toEqual(1); + + removeEventListener('click', listener); + button.dispatchEvent(clickEvent); + expect(callCount).toEqual(1); + }); + it('should work with addEventListener when called with a function listener', function () { var clickEvent = document.createEvent('Event'); clickEvent.initEvent('click', true, true);