diff --git a/src/core/services/interaction/interaction.js b/src/core/services/interaction/interaction.js index 845012c9c96..bf948917610 100644 --- a/src/core/services/interaction/interaction.js +++ b/src/core/services/interaction/interaction.js @@ -33,15 +33,20 @@ angular * * */ -function MdInteractionService($timeout, $mdUtil) { +function MdInteractionService($timeout, $mdUtil, $rootScope) { this.$timeout = $timeout; this.$mdUtil = $mdUtil; + this.$rootScope = $rootScope; + // IE browsers can also trigger pointer events, which also leads to an interaction. + this.pointerEvent = 'MSPointerEvent' in window ? 'MSPointerDown' : 'PointerEvent' in window ? 'pointerdown' : null; this.bodyElement = angular.element(document.body); this.isBuffering = false; this.bufferTimeout = null; this.lastInteractionType = null; this.lastInteractionTime = null; + this.inputHandler = this.onInputEvent.bind(this); + this.bufferedInputHandler = this.onBufferInputEvent.bind(this); // Type Mappings for the different events // There will be three three interaction types @@ -65,24 +70,41 @@ function MdInteractionService($timeout, $mdUtil) { }; this.initializeEvents(); + this.$rootScope.$on('$destroy', this.deregister.bind(this)); } +/** + * Removes all event listeners created by $mdInteration on the + * body element. + */ +MdInteractionService.prototype.deregister = function() { + + this.bodyElement.off('keydown mousedown', this.inputHandler); + + if ('ontouchstart' in document.documentElement) { + this.bodyElement.off('touchstart', this.bufferedInputHandler); + } + + if (this.pointerEvent) { + this.bodyElement.off(this.pointerEvent, this.inputHandler); + } + +}; + /** * Initializes the interaction service, by registering all interaction events to the * body element. */ MdInteractionService.prototype.initializeEvents = function() { - // IE browsers can also trigger pointer events, which also leads to an interaction. - var pointerEvent = 'MSPointerEvent' in window ? 'MSPointerDown' : 'PointerEvent' in window ? 'pointerdown' : null; - this.bodyElement.on('keydown mousedown', this.onInputEvent.bind(this)); + this.bodyElement.on('keydown mousedown', this.inputHandler); if ('ontouchstart' in document.documentElement) { - this.bodyElement.on('touchstart', this.onBufferInputEvent.bind(this)); + this.bodyElement.on('touchstart', this.bufferedInputHandler); } - if (pointerEvent) { - this.bodyElement.on(pointerEvent, this.onInputEvent.bind(this)); + if (this.pointerEvent) { + this.bodyElement.on(this.pointerEvent, this.inputHandler); } }; diff --git a/src/core/services/interaction/interaction.spec.js b/src/core/services/interaction/interaction.spec.js index 6124c98f034..b432017859b 100644 --- a/src/core/services/interaction/interaction.spec.js +++ b/src/core/services/interaction/interaction.spec.js @@ -1,12 +1,16 @@ describe("$mdInteraction service", function() { var $mdInteraction = null; + var $rootScope = null; var bodyElement = null; + var $timeout = null; beforeEach(module('material.core')); beforeEach(inject(function($injector) { $mdInteraction = $injector.get('$mdInteraction'); + $rootScope = $injector.get('$rootScope'); + $timeout = $injector.get('$timeout'); bodyElement = angular.element(document.body); })); @@ -75,4 +79,38 @@ describe("$mdInteraction service", function() { }); -}); \ No newline at end of file + describe('when $rootScope is destroyed', function () { + + var _initialTouchStartEvent = document.documentElement.ontouchstart; + + beforeAll(function () { + document.documentElement.ontouchstart = function () {}; + }); + + beforeEach(function () { + $mdInteraction.lastInteractionType = 'initial'; + $rootScope.$destroy(); + }); + + afterAll(function () { + document.documentElement.ontouchstart = _initialTouchStartEvent; + }); + + it('should remove mousedown events', function () { + bodyElement.triggerHandler('mousedown'); + expect($mdInteraction.getLastInteractionType()).toEqual('initial'); + }); + + it('should remove keydown events', function () { + bodyElement.triggerHandler('keydown'); + expect($mdInteraction.getLastInteractionType()).toEqual('initial'); + }); + + it('should remove touchstart events', function () { + bodyElement.triggerHandler('touchstart'); + expect($mdInteraction.getLastInteractionType()).toEqual('initial'); + }); + + }); + +});