diff --git a/lib/common/utils.ts b/lib/common/utils.ts index 2d292bf4f..c183fe5a6 100644 --- a/lib/common/utils.ts +++ b/lib/common/utils.ts @@ -21,6 +21,7 @@ const _global: any = const FUNCTION = 'function'; const UNDEFINED = 'undefined'; const REMOVE_ATTRIBUTE = 'removeAttribute'; +const NULL_ON_PROP_VALUE: any[] = [null]; export function bindArguments(args: any[], source: string): any[] { for (let i = args.length - 1; i >= 0; i--) { @@ -141,6 +142,7 @@ export function patchProperty(obj: any, prop: string, prototype?: any) { delete desc.writable; delete desc.value; const originalDescGet = desc.get; + const originalDescSet = desc.set; // substr(2) cuz 'onclick' -> 'click', etc const eventName = prop.substr(2); @@ -165,6 +167,12 @@ export function patchProperty(obj: any, prop: string, prototype?: any) { target.removeEventListener(eventName, wrapFn); } + // issue #978, when onload handler was added before loading zone.js + // we should remove it with originalDescSet + if (originalDescSet) { + originalDescSet.apply(target, NULL_ON_PROP_VALUE); + } + if (typeof newValue === 'function') { target[eventNameSymbol] = newValue; target.addEventListener(eventName, wrapFn, false); diff --git a/test/browser/browser.spec.ts b/test/browser/browser.spec.ts index b59337542..5365aeb21 100644 --- a/test/browser/browser.spec.ts +++ b/test/browser/browser.spec.ts @@ -225,6 +225,29 @@ describe('Zone', function() { }); }); + it('should be able to clear on handler added before load zone.js', function() { + const TestTarget: any = (window as any)['TestTarget']; + patchFilteredProperties( + TestTarget.prototype, ['prop3'], global['__Zone_ignore_on_properties']); + const testTarget = new TestTarget(); + Zone.current.fork({name: 'test'}).run(() => { + expect(testTarget.onprop3).toBeTruthy(); + const newProp3Handler = function() {}; + testTarget.onprop3 = newProp3Handler; + expect(testTarget.onprop3).toBe(newProp3Handler); + testTarget.onprop3 = null; + expect(!testTarget.onprop3).toBeTruthy(); + testTarget.onprop3 = function() { + // onprop1 should not be patched + expect(Zone.current.name).toEqual('test'); + }; + }); + + Zone.current.fork({name: 'test1'}).run(() => { + testTarget.dispatchEvent('prop3'); + }); + }); + it('window onclick should be in zone', ifEnvSupports(canPatchOnProperty(window, 'onmousedown'), function() { zone.run(function() { diff --git a/test/test_fake_polyfill.ts b/test/test_fake_polyfill.ts index 75be59dce..e5e92c4f0 100644 --- a/test/test_fake_polyfill.ts +++ b/test/test_fake_polyfill.ts @@ -32,6 +32,16 @@ Object.defineProperties(TestTarget.prototype, { 'onprop1': {configurable: true, writable: true}, 'onprop2': {configurable: true, writable: true}, + 'onprop3': { + configurable: true, + get: function() { + return this._onprop3; + }, + set: function(_value) { + this._onprop3 = _value; + } + }, + '_onprop3': {configurable: true, writable: true, value: function() {}}, 'addEventListener': { configurable: true, writable: true,