diff --git a/packages/zone.js/lib/common/events.ts b/packages/zone.js/lib/common/events.ts index 0c27767e785a3..89fa6a856a2f1 100644 --- a/packages/zone.js/lib/common/events.ts +++ b/packages/zone.js/lib/common/events.ts @@ -576,8 +576,10 @@ export function patchEventTarget( target[symbolEventName] = null; // in the target, we have an event listener which is added by on_property // such as target.onclick = function() {}, so we need to clear this internal - // property too if all delegates all removed - if (typeof eventName === 'string') { + // property too if all delegates with capture=false were removed + // https:// github.com/angular/angular/issues/31643 + // https://github.com/angular/angular/issues/54581 + if (!capture && typeof eventName === 'string') { const onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName; target[onPropertySymbol] = null; } diff --git a/packages/zone.js/test/browser/browser.spec.ts b/packages/zone.js/test/browser/browser.spec.ts index 974d2d4ce44fc..bcdc69983d8c0 100644 --- a/packages/zone.js/test/browser/browser.spec.ts +++ b/packages/zone.js/test/browser/browser.spec.ts @@ -2046,6 +2046,41 @@ describe('Zone', function() { }); }); + it('should not remove onEventListener when removing capture listener', function() { + const button = document.createElement('button'); + document.body.append(button); + const createEvt = () => { + const evt = document.createEvent('Event'); + evt.initEvent('click', true, true); + return evt; + }; + let logs: string[] = []; + const onClickHandler = () => logs.push('onclick'); + button.onclick = onClickHandler; + let evt = createEvt(); + button.dispatchEvent(evt); + expect(logs).toEqual(['onclick']); + logs = []; + const listener = () => logs.push('click listener'); + button.addEventListener('click', listener, {capture: true}); + evt = createEvt(); + button.dispatchEvent(evt); + expect(logs.sort()).toEqual(['onclick', 'click listener'].sort()); + logs = []; + button.removeEventListener('click', listener, true); + evt = createEvt(); + button.dispatchEvent(evt); + expect(logs).toEqual(['onclick']); + expect(button.onclick).toBe(onClickHandler); + button.onclick = null; + logs = []; + evt = createEvt(); + button.dispatchEvent(evt); + expect(logs).toEqual([]); + expect(button.onclick).toBe(null); + document.body.removeChild(button); + }); + describe('should be able to remove eventListener during eventListener callback', function() { it('should be able to remove eventListener during eventListener callback', function() { let logs: string[] = [];