diff --git a/src/timepicker/test/timepicker.spec.js b/src/timepicker/test/timepicker.spec.js index bc310ad7ad..21ccfeabd8 100644 --- a/src/timepicker/test/timepicker.spec.js +++ b/src/timepicker/test/timepicker.spec.js @@ -2191,4 +2191,21 @@ describe('timepicker directive', function() { expect(getModelState()).toEqual([14, 40, 25]); }); }); + + describe('gc', function() { + var $scope; + beforeEach(inject(function() { + $scope = $rootScope.$new(); + element = $compile('')($scope); + $rootScope.$digest(); + })); + + it('should clean up watchers', function() { + expect($scope.$$watchers.length > 1).toBe(true); + + element.isolateScope().$destroy(); + + expect($scope.$$watchers.length).toBe(1); + }); + }); }); diff --git a/src/timepicker/timepicker.js b/src/timepicker/timepicker.js index c243e45bd3..e969d05126 100644 --- a/src/timepicker/timepicker.js +++ b/src/timepicker/timepicker.js @@ -16,8 +16,9 @@ angular.module('ui.bootstrap.timepicker', []) .controller('UibTimepickerController', ['$scope', '$element', '$attrs', '$parse', '$log', '$locale', 'uibTimepickerConfig', function($scope, $element, $attrs, $parse, $log, $locale, timepickerConfig) { var selected = new Date(), - ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl - meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS; + watchers = [], + ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl + meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS; $scope.tabindex = angular.isDefined($attrs.tabindex) ? $attrs.tabindex : 0; $element.removeAttr('tabindex'); @@ -51,35 +52,35 @@ angular.module('ui.bootstrap.timepicker', []) var hourStep = timepickerConfig.hourStep; if ($attrs.hourStep) { - $scope.$parent.$watch($parse($attrs.hourStep), function(value) { + watchers.push($scope.$parent.$watch($parse($attrs.hourStep), function(value) { hourStep = +value; - }); + })); } var minuteStep = timepickerConfig.minuteStep; if ($attrs.minuteStep) { - $scope.$parent.$watch($parse($attrs.minuteStep), function(value) { + watchers.push($scope.$parent.$watch($parse($attrs.minuteStep), function(value) { minuteStep = +value; - }); + })); } var min; - $scope.$parent.$watch($parse($attrs.min), function(value) { + watchers.push($scope.$parent.$watch($parse($attrs.min), function(value) { var dt = new Date(value); min = isNaN(dt) ? undefined : dt; - }); + })); var max; - $scope.$parent.$watch($parse($attrs.max), function(value) { + watchers.push($scope.$parent.$watch($parse($attrs.max), function(value) { var dt = new Date(value); max = isNaN(dt) ? undefined : dt; - }); + })); var disabled = false; if ($attrs.ngDisabled) { - $scope.$parent.$watch($parse($attrs.ngDisabled), function(value) { + watchers.push($scope.$parent.$watch($parse($attrs.ngDisabled), function(value) { disabled = value; - }); + })); } $scope.noIncrementHours = function() { @@ -128,22 +129,22 @@ angular.module('ui.bootstrap.timepicker', []) var secondStep = timepickerConfig.secondStep; if ($attrs.secondStep) { - $scope.$parent.$watch($parse($attrs.secondStep), function(value) { + watchers.push($scope.$parent.$watch($parse($attrs.secondStep), function(value) { secondStep = +value; - }); + })); } $scope.showSeconds = timepickerConfig.showSeconds; if ($attrs.showSeconds) { - $scope.$parent.$watch($parse($attrs.showSeconds), function(value) { + watchers.push($scope.$parent.$watch($parse($attrs.showSeconds), function(value) { $scope.showSeconds = !!value; - }); + })); } // 12H / 24H mode $scope.showMeridian = timepickerConfig.showMeridian; if ($attrs.showMeridian) { - $scope.$parent.$watch($parse($attrs.showMeridian), function(value) { + watchers.push($scope.$parent.$watch($parse($attrs.showMeridian), function(value) { $scope.showMeridian = !!value; if (ngModelCtrl.$error.time) { @@ -156,7 +157,7 @@ angular.module('ui.bootstrap.timepicker', []) } else { updateTemplate(); } - }); + })); } // Get $scope.hours in 24H mode if valid @@ -518,6 +519,12 @@ angular.module('ui.bootstrap.timepicker', []) $scope.blur = function() { ngModelCtrl.$setTouched(); }; + + $scope.$on('$destroy', function() { + while (watchers.length) { + watchers.shift()(); + } + }); }]) .directive('uibTimepicker', ['uibTimepickerConfig', function(uibTimepickerConfig) {