diff --git a/src/jqLite.js b/src/jqLite.js index e59805147886..102ded7c2953 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -863,7 +863,9 @@ forEach({ clone: jqLiteClone, triggerHandler: function(element, eventName, eventData) { - var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName]; + // Copy event handlers in case event handlers array is modified during execution. + var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName], + eventFnsCopy = shallowCopy(eventFns || []); eventData = eventData || []; @@ -872,7 +874,7 @@ forEach({ stopPropagation: noop }]; - forEach(eventFns, function(fn) { + forEach(eventFnsCopy, function(fn) { fn.apply(element, event.concat(eventData)); }); } diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index 931f9b2e5cb3..a962b51599b3 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1503,6 +1503,26 @@ describe('jqLite', function() { data = pokeSpy.mostRecentCall.args[1]; expect(data.hello).toBe("world"); }); + + it('should support handlers that deregister themselves', function() { + var element = jqLite('poke'), + clickSpy = jasmine.createSpy('click'), + clickOnceSpy = jasmine.createSpy('clickOnce').andCallFake(function() { + element.off('click', clickOnceSpy); + }); + + element.on('click', clickOnceSpy); + element.on('click', clickSpy); + + element.triggerHandler('click'); + expect(clickOnceSpy).toHaveBeenCalledOnce(); + expect(clickSpy).toHaveBeenCalledOnce(); + + element.triggerHandler('click'); + expect(clickOnceSpy).toHaveBeenCalledOnce(); + expect(clickSpy.callCount).toBe(2); + }); + });