diff options
| author | Pete Bacon Darwin | 2013-12-17 22:53:28 +0000 |
|---|---|---|
| committer | Pete Bacon Darwin | 2013-12-17 22:53:28 +0000 |
| commit | 73c66715c9a13b0fdacf98a9e9f237063a97ebc3 (patch) | |
| tree | 4067f429946d0a99c82ae1ad1f7917ae5c62e4b9 | |
| parent | cb29632a5802e930262919b3db64ca4806c5cfc7 (diff) | |
| download | angular.js-73c66715c9a13b0fdacf98a9e9f237063a97ebc3.tar.bz2 | |
docs(bootstrap-prettify): fix $timeout issues and update related docs
End 2 end tests wait for all `$timeout`s to be run before completing the test.
This was problematic where we were using timeouts that restarted themselves because
there would never be a point when all timeouts had completed, causing the tests to hang.
To fix this $timeout had been monkey-patched but this caused other issue itself.
Now that we have $interval we don't need to use $timeout handlers that re-trigger the $timeout
so we can ditch the monkey-patch.
This commit tidies up any examples that are using this approach and changes them to use $interval
instead.
Closes #5232
| -rw-r--r-- | docs/components/angular-bootstrap/bootstrap-prettify.js | 12 | ||||
| -rw-r--r-- | docs/content/guide/dev_guide.services.managing_dependencies.ngdoc | 7 | ||||
| -rw-r--r-- | docs/content/guide/directive.ngdoc | 26 | ||||
| -rw-r--r-- | docs/content/guide/scope.ngdoc | 4 | ||||
| -rw-r--r-- | src/ng/interval.js | 82 | ||||
| -rw-r--r-- | src/ng/timeout.js | 87 |
6 files changed, 99 insertions, 119 deletions
diff --git a/docs/components/angular-bootstrap/bootstrap-prettify.js b/docs/components/angular-bootstrap/bootstrap-prettify.js index 72c136d1..5129c4e1 100644 --- a/docs/components/angular-bootstrap/bootstrap-prettify.js +++ b/docs/components/angular-bootstrap/bootstrap-prettify.js @@ -215,17 +215,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', }]; this.html5Mode = angular.noop; }); - $provide.decorator('$timeout', ['$rootScope', '$delegate', function($rootScope, $delegate) { - return angular.extend(function(fn, delay) { - if (delay && delay > 50) { - return setTimeout(function() { - $rootScope.$apply(fn); - }, delay); - } else { - return $delegate.apply(this, arguments); - } - }, $delegate); - }]); + $provide.decorator('$rootScope', ['$delegate', function($delegate) { embedRootScope = $delegate; diff --git a/docs/content/guide/dev_guide.services.managing_dependencies.ngdoc b/docs/content/guide/dev_guide.services.managing_dependencies.ngdoc index b069f4bb..a0d95d4a 100644 --- a/docs/content/guide/dev_guide.services.managing_dependencies.ngdoc +++ b/docs/content/guide/dev_guide.services.managing_dependencies.ngdoc @@ -50,7 +50,7 @@ of which depend on other services that are provided by the Angular framework: * @param {*} message Message to be logged. */ function batchLogModule($provide){ - $provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) { + $provide.factory('batchLog', ['$interval', '$log', function($interval, $log) { var messageQueue = []; function log() { @@ -58,11 +58,10 @@ of which depend on other services that are provided by the Angular framework: $log('batchLog messages: ', messageQueue); messageQueue = []; } - $timeout(log, 50000); } // start periodic checking - log(); + $interval(log, 50000); return function(message) { messageQueue.push(message); @@ -88,7 +87,7 @@ of which depend on other services that are provided by the Angular framework: Things to notice in this example: -* The `batchLog` service depends on the built-in {@link api/ng.$timeout $timeout} and +* The `batchLog` service depends on the built-in {@link api/ng.$interval $interval} and {@link api/ng.$log $log} services, and allows messages to be logged into the `console.log` in batches. * The `routeTemplateMonitor` service depends on the built-in {@link api/ngRoute.$route diff --git a/docs/content/guide/directive.ngdoc b/docs/content/guide/directive.ngdoc index b6b74a97..b3925bfc 100644 --- a/docs/content/guide/directive.ngdoc +++ b/docs/content/guide/directive.ngdoc @@ -528,8 +528,10 @@ where: * `attrs` is an object with the normalized attribute names and their corresponding values. In our `link` function, we want to update the displayed time once a second, or whenever a user -changes the time formatting string that our directive binds to. We also want to remove the timeout -if the directive is deleted so we don't introduce a memory leak. +changes the time formatting string that our directive binds to. We will use the `$interval` service +to call a handler on a regular basis. This is easier than using `$timeout` but also works better with +end 2 end testing, where we want to ensure that all $timeouts have completed before completing the test. +We also want to remove the `$interval` if the directive is deleted so we don't introduce a memory leak. <example module="docsTimeDirective"> <file name="script.js"> @@ -537,7 +539,7 @@ if the directive is deleted so we don't introduce a memory leak. .controller('Ctrl2', function($scope) { $scope.format = 'M/d/yy h:mm:ss a'; }) - .directive('myCurrentTime', function($timeout, dateFilter) { + .directive('myCurrentTime', function($interval, dateFilter) { function link(scope, element, attrs) { var format, @@ -552,20 +554,14 @@ if the directive is deleted so we don't introduce a memory leak. updateTime(); }); - function scheduleUpdate() { - // save the timeoutId for canceling - timeoutId = $timeout(function() { - updateTime(); // update DOM - scheduleUpdate(); // schedule the next update - }, 1000); - } - element.on('$destroy', function() { - $timeout.cancel(timeoutId); + $interval.cancel(timeoutId); }); - // start the UI update process. - scheduleUpdate(); + // start the UI update process; save the timeoutId for canceling + timeoutId = $interval(function() { + updateTime(); // update DOM + }, 1000); } return { @@ -583,7 +579,7 @@ if the directive is deleted so we don't introduce a memory leak. There are a couple of things to note here. Just like the `module.controller` API, the function argument in `module.directive` is dependency -injected. Because of this, we can use `$timeout` and `dateFilter` inside our directive's `link` +injected. Because of this, we can use `$interval` and `dateFilter` inside our directive's `link` function. We register an event `element.on('$destroy', ...)`. What fires this `$destroy` event? diff --git a/docs/content/guide/scope.ngdoc b/docs/content/guide/scope.ngdoc index 70224c82..da35a1b8 100644 --- a/docs/content/guide/scope.ngdoc +++ b/docs/content/guide/scope.ngdoc @@ -259,8 +259,8 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model For mutations to be properly observed, you should make them only within the {@link api/ng.$rootScope.Scope#methods_$apply scope.$apply()}. (Angular APIs do this implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers, - or asynchronous work with {@link api/ng.$http $http} or {@link - api/ng.$timeout $timeout} services. + or asynchronous work with {@link api/ng.$http $http}, {@link api/ng.$timeout $timeout} + or {@link api/ng.$interval $interval} services. 4. **Mutation observation** diff --git a/src/ng/interval.js b/src/ng/interval.js index 2ad3a7f1..1ae13648 100644 --- a/src/ng/interval.js +++ b/src/ng/interval.js @@ -32,6 +32,88 @@ function $IntervalProvider() { * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block. * @returns {promise} A promise which will be notified on each iteration. + * + * @example + <doc:example module="time"> + <doc:source> + <script> + function Ctrl2($scope,$interval) { + $scope.format = 'M/d/yy h:mm:ss a'; + $scope.blood_1 = 100; + $scope.blood_2 = 120; + + var stop; + $scope.fight = function() { + // Don't start a new fight if we are already fighting + if ( angular.isDefined(stop) ) return; + + stop = $interval(function() { + if ($scope.blood_1 > 0 && $scope.blood_2 > 0) { + $scope.blood_1 = $scope.blood_1 - 3; + $scope.blood_2 = $scope.blood_2 - 4; + } else { + $interval.cancel(stop); + } + }, 100); + }; + + $scope.stopFight = function() { + $interval.cancel(stop); + stop = undefined; + }; + + $scope.resetFight = function() { + $scope.blood_1 = 100; + $scope.blood_2 = 120; + } + } + + angular.module('time', []) + // Register the 'myCurrentTime' directive factory method. + // We inject $interval and dateFilter service since the factory method is DI. + .directive('myCurrentTime', function($interval, dateFilter) { + // return the directive link function. (compile function not needed) + return function(scope, element, attrs) { + var format, // date format + stopTime; // so that we can cancel the time updates + + // used to update the UI + function updateTime() { + element.text(dateFilter(new Date(), format)); + } + + // watch the expression, and update the UI on change. + scope.$watch(attrs.myCurrentTime, function(value) { + format = value; + updateTime(); + }); + + stopTime = $interval(updateTime, 1000); + + // listen on DOM destroy (removal) event, and cancel the next UI update + // to prevent updating time ofter the DOM element was removed. + element.bind('$destroy', function() { + $interval.cancel(stopTime); + }); + } + }); + </script> + + <div> + <div ng-controller="Ctrl2"> + Date format: <input ng-model="format"> <hr/> + Current time is: <span my-current-time="format"></span> + <hr/> + Blood 1 : <font color='red'>{{blood_1}}</font> + Blood 2 : <font color='red'>{{blood_2}}</font> + <button type="button" data-ng-click="fight()">Fight</button> + <button type="button" data-ng-click="stopFight()">StopFight</button> + <button type="button" data-ng-click="resetFight()">resetFight</button> + </div> + </div> + + </doc:source> + </doc:example> */ function interval(fn, delay, count, invokeApply) { var setInterval = $window.setInterval, diff --git a/src/ng/timeout.js b/src/ng/timeout.js index 51e627b9..511a0a05 100644 --- a/src/ng/timeout.js +++ b/src/ng/timeout.js @@ -32,93 +32,6 @@ function $TimeoutProvider() { * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this * promise will be resolved with is the return value of the `fn` function. * - * @example - <doc:example module="time"> - <doc:source> - <script> - function Ctrl2($scope,$timeout) { - $scope.format = 'M/d/yy h:mm:ss a'; - $scope.blood_1 = 100; - $scope.blood_2 = 120; - - var stop; - $scope.fight = function() { - stop = $timeout(function() { - if ($scope.blood_1 > 0 && $scope.blood_2 > 0) { - $scope.blood_1 = $scope.blood_1 - 3; - $scope.blood_2 = $scope.blood_2 - 4; - $scope.fight(); - } else { - $timeout.cancel(stop); - } - }, 100); - }; - - $scope.stopFight = function() { - $timeout.cancel(stop); - }; - - $scope.resetFight = function() { - $scope.blood_1 = 100; - $scope.blood_2 = 120; - } - } - - angular.module('time', []) - // Register the 'myCurrentTime' directive factory method. - // We inject $timeout and dateFilter service since the factory method is DI. - .directive('myCurrentTime', function($timeout, dateFilter) { - // return the directive link function. (compile function not needed) - return function(scope, element, attrs) { - var format, // date format - timeoutId; // timeoutId, so that we can cancel the time updates - - // used to update the UI - function updateTime() { - element.text(dateFilter(new Date(), format)); - } - - // watch the expression, and update the UI on change. - scope.$watch(attrs.myCurrentTime, function(value) { - format = value; - updateTime(); - }); - - // schedule update in one second - function updateLater() { - // save the timeoutId for canceling - timeoutId = $timeout(function() { - updateTime(); // update DOM - updateLater(); // schedule another update - }, 1000); - } - - // listen on DOM destroy (removal) event, and cancel the next UI update - // to prevent updating time ofter the DOM element was removed. - element.bind('$destroy', function() { - $timeout.cancel(timeoutId); - }); - - updateLater(); // kick off the UI update process. - } - }); - </script> - - <div> - <div ng-controller="Ctrl2"> - Date format: <input ng-model="format"> <hr/> - Current time is: <span my-current-time="format"></span> - <hr/> - Blood 1 : <font color='red'>{{blood_1}}</font> - Blood 2 : <font color='red'>{{blood_2}}</font> - <button type="button" data-ng-click="fight()">Fight</button> - <button type="button" data-ng-click="stopFight()">StopFight</button> - <button type="button" data-ng-click="resetFight()">resetFight</button> - </div> - </div> - - </doc:source> - </doc:example> */ function timeout(fn, delay, invokeApply) { var deferred = $q.defer(), |
