diff --git a/src/jqLite.js b/src/jqLite.js index 9d342bfb..1fe2e4a0 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -948,7 +948,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 || []; @@ -962,7 +964,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 3124b47a..942e0ead 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -1743,6 +1743,26 @@ describe('jqLite', function() { event.preventDefault(); expect(event.isDefaultPrevented()).toBe(true); }); + + + 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); + }); });