Skip to content

Commit 2cd56b4

Browse files
petebacondarwinjamesdaily
authored andcommitted
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 angular#5232
1 parent 879ef2b commit 2cd56b4

File tree

6 files changed

+99
-119
lines changed

6 files changed

+99
-119
lines changed

docs/components/angular-bootstrap/bootstrap-prettify.js

+1-11
Original file line numberDiff line numberDiff line change
@@ -215,17 +215,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
215215
}];
216216
this.html5Mode = angular.noop;
217217
});
218-
$provide.decorator('$timeout', ['$rootScope', '$delegate', function($rootScope, $delegate) {
219-
return angular.extend(function(fn, delay) {
220-
if (delay && delay > 50) {
221-
return setTimeout(function() {
222-
$rootScope.$apply(fn);
223-
}, delay);
224-
} else {
225-
return $delegate.apply(this, arguments);
226-
}
227-
}, $delegate);
228-
}]);
218+
229219
$provide.decorator('$rootScope', ['$delegate', function($delegate) {
230220
embedRootScope = $delegate;
231221

docs/content/guide/dev_guide.services.managing_dependencies.ngdoc

+3-4
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,18 @@ of which depend on other services that are provided by the Angular framework:
5050
* @param {*} message Message to be logged.
5151
*/
5252
function batchLogModule($provide){
53-
$provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) {
53+
$provide.factory('batchLog', ['$interval', '$log', function($interval, $log) {
5454
var messageQueue = [];
5555

5656
function log() {
5757
if (messageQueue.length) {
5858
$log('batchLog messages: ', messageQueue);
5959
messageQueue = [];
6060
}
61-
$timeout(log, 50000);
6261
}
6362

6463
// start periodic checking
65-
log();
64+
$interval(log, 50000);
6665

6766
return function(message) {
6867
messageQueue.push(message);
@@ -88,7 +87,7 @@ of which depend on other services that are provided by the Angular framework:
8887

8988
Things to notice in this example:
9089

91-
* The `batchLog` service depends on the built-in {@link api/ng.$timeout $timeout} and
90+
* The `batchLog` service depends on the built-in {@link api/ng.$interval $interval} and
9291
{@link api/ng.$log $log} services, and allows messages to be logged into the
9392
`console.log` in batches.
9493
* The `routeTemplateMonitor` service depends on the built-in {@link api/ngRoute.$route

docs/content/guide/directive.ngdoc

+11-15
Original file line numberDiff line numberDiff line change
@@ -528,16 +528,18 @@ where:
528528
* `attrs` is an object with the normalized attribute names and their corresponding values.
529529

530530
In our `link` function, we want to update the displayed time once a second, or whenever a user
531-
changes the time formatting string that our directive binds to. We also want to remove the timeout
532-
if the directive is deleted so we don't introduce a memory leak.
531+
changes the time formatting string that our directive binds to. We will use the `$interval` service
532+
to call a handler on a regular basis. This is easier than using `$timeout` but also works better with
533+
end 2 end testing, where we want to ensure that all $timeouts have completed before completing the test.
534+
We also want to remove the `$interval` if the directive is deleted so we don't introduce a memory leak.
533535

534536
<example module="docsTimeDirective">
535537
<file name="script.js">
536538
angular.module('docsTimeDirective', [])
537539
.controller('Ctrl2', function($scope) {
538540
$scope.format = 'M/d/yy h:mm:ss a';
539541
})
540-
.directive('myCurrentTime', function($timeout, dateFilter) {
542+
.directive('myCurrentTime', function($interval, dateFilter) {
541543

542544
function link(scope, element, attrs) {
543545
var format,
@@ -552,20 +554,14 @@ if the directive is deleted so we don't introduce a memory leak.
552554
updateTime();
553555
});
554556

555-
function scheduleUpdate() {
556-
// save the timeoutId for canceling
557-
timeoutId = $timeout(function() {
558-
updateTime(); // update DOM
559-
scheduleUpdate(); // schedule the next update
560-
}, 1000);
561-
}
562-
563557
element.on('$destroy', function() {
564-
$timeout.cancel(timeoutId);
558+
$interval.cancel(timeoutId);
565559
});
566560

567-
// start the UI update process.
568-
scheduleUpdate();
561+
// start the UI update process; save the timeoutId for canceling
562+
timeoutId = $interval(function() {
563+
updateTime(); // update DOM
564+
}, 1000);
569565
}
570566

571567
return {
@@ -583,7 +579,7 @@ if the directive is deleted so we don't introduce a memory leak.
583579

584580
There are a couple of things to note here.
585581
Just like the `module.controller` API, the function argument in `module.directive` is dependency
586-
injected. Because of this, we can use `$timeout` and `dateFilter` inside our directive's `link`
582+
injected. Because of this, we can use `$interval` and `dateFilter` inside our directive's `link`
587583
function.
588584

589585
We register an event `element.on('$destroy', ...)`. What fires this `$destroy` event?

docs/content/guide/scope.ngdoc

+2-2
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,8 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
259259
For mutations to be properly observed, you should make them only within the {@link
260260
api/ng.$rootScope.Scope#methods_$apply scope.$apply()}. (Angular APIs do this
261261
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
262-
or asynchronous work with {@link api/ng.$http $http} or {@link
263-
api/ng.$timeout $timeout} services.
262+
or asynchronous work with {@link api/ng.$http $http}, {@link api/ng.$timeout $timeout}
263+
or {@link api/ng.$interval $interval} services.
264264

265265
4. **Mutation observation**
266266

src/ng/interval.js

+82
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,88 @@ function $IntervalProvider() {
3232
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
3333
* will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
3434
* @returns {promise} A promise which will be notified on each iteration.
35+
*
36+
* @example
37+
<doc:example module="time">
38+
<doc:source>
39+
<script>
40+
function Ctrl2($scope,$interval) {
41+
$scope.format = 'M/d/yy h:mm:ss a';
42+
$scope.blood_1 = 100;
43+
$scope.blood_2 = 120;
44+
45+
var stop;
46+
$scope.fight = function() {
47+
// Don't start a new fight if we are already fighting
48+
if ( angular.isDefined(stop) ) return;
49+
50+
stop = $interval(function() {
51+
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
52+
$scope.blood_1 = $scope.blood_1 - 3;
53+
$scope.blood_2 = $scope.blood_2 - 4;
54+
} else {
55+
$interval.cancel(stop);
56+
}
57+
}, 100);
58+
};
59+
60+
$scope.stopFight = function() {
61+
$interval.cancel(stop);
62+
stop = undefined;
63+
};
64+
65+
$scope.resetFight = function() {
66+
$scope.blood_1 = 100;
67+
$scope.blood_2 = 120;
68+
}
69+
}
70+
71+
angular.module('time', [])
72+
// Register the 'myCurrentTime' directive factory method.
73+
// We inject $interval and dateFilter service since the factory method is DI.
74+
.directive('myCurrentTime', function($interval, dateFilter) {
75+
// return the directive link function. (compile function not needed)
76+
return function(scope, element, attrs) {
77+
var format, // date format
78+
stopTime; // so that we can cancel the time updates
79+
80+
// used to update the UI
81+
function updateTime() {
82+
element.text(dateFilter(new Date(), format));
83+
}
84+
85+
// watch the expression, and update the UI on change.
86+
scope.$watch(attrs.myCurrentTime, function(value) {
87+
format = value;
88+
updateTime();
89+
});
90+
91+
stopTime = $interval(updateTime, 1000);
92+
93+
// listen on DOM destroy (removal) event, and cancel the next UI update
94+
// to prevent updating time ofter the DOM element was removed.
95+
element.bind('$destroy', function() {
96+
$interval.cancel(stopTime);
97+
});
98+
}
99+
});
100+
</script>
101+
102+
<div>
103+
<div ng-controller="Ctrl2">
104+
Date format: <input ng-model="format"> <hr/>
105+
Current time is: <span my-current-time="format"></span>
106+
<hr/>
107+
Blood 1 : <font color='red'>{{blood_1}}</font>
108+
Blood 2 : <font color='red'>{{blood_2}}</font>
109+
<button type="button" data-ng-click="fight()">Fight</button>
110+
<button type="button" data-ng-click="stopFight()">StopFight</button>
111+
<button type="button" data-ng-click="resetFight()">resetFight</button>
112+
</div>
113+
</div>
114+
115+
</doc:source>
116+
</doc:example>
35117
*/
36118
function interval(fn, delay, count, invokeApply) {
37119
var setInterval = $window.setInterval,

src/ng/timeout.js

-87
Original file line numberDiff line numberDiff line change
@@ -32,93 +32,6 @@ function $TimeoutProvider() {
3232
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
3333
* promise will be resolved with is the return value of the `fn` function.
3434
*
35-
* @example
36-
<doc:example module="time">
37-
<doc:source>
38-
<script>
39-
function Ctrl2($scope,$timeout) {
40-
$scope.format = 'M/d/yy h:mm:ss a';
41-
$scope.blood_1 = 100;
42-
$scope.blood_2 = 120;
43-
44-
var stop;
45-
$scope.fight = function() {
46-
stop = $timeout(function() {
47-
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
48-
$scope.blood_1 = $scope.blood_1 - 3;
49-
$scope.blood_2 = $scope.blood_2 - 4;
50-
$scope.fight();
51-
} else {
52-
$timeout.cancel(stop);
53-
}
54-
}, 100);
55-
};
56-
57-
$scope.stopFight = function() {
58-
$timeout.cancel(stop);
59-
};
60-
61-
$scope.resetFight = function() {
62-
$scope.blood_1 = 100;
63-
$scope.blood_2 = 120;
64-
}
65-
}
66-
67-
angular.module('time', [])
68-
// Register the 'myCurrentTime' directive factory method.
69-
// We inject $timeout and dateFilter service since the factory method is DI.
70-
.directive('myCurrentTime', function($timeout, dateFilter) {
71-
// return the directive link function. (compile function not needed)
72-
return function(scope, element, attrs) {
73-
var format, // date format
74-
timeoutId; // timeoutId, so that we can cancel the time updates
75-
76-
// used to update the UI
77-
function updateTime() {
78-
element.text(dateFilter(new Date(), format));
79-
}
80-
81-
// watch the expression, and update the UI on change.
82-
scope.$watch(attrs.myCurrentTime, function(value) {
83-
format = value;
84-
updateTime();
85-
});
86-
87-
// schedule update in one second
88-
function updateLater() {
89-
// save the timeoutId for canceling
90-
timeoutId = $timeout(function() {
91-
updateTime(); // update DOM
92-
updateLater(); // schedule another update
93-
}, 1000);
94-
}
95-
96-
// listen on DOM destroy (removal) event, and cancel the next UI update
97-
// to prevent updating time ofter the DOM element was removed.
98-
element.bind('$destroy', function() {
99-
$timeout.cancel(timeoutId);
100-
});
101-
102-
updateLater(); // kick off the UI update process.
103-
}
104-
});
105-
</script>
106-
107-
<div>
108-
<div ng-controller="Ctrl2">
109-
Date format: <input ng-model="format"> <hr/>
110-
Current time is: <span my-current-time="format"></span>
111-
<hr/>
112-
Blood 1 : <font color='red'>{{blood_1}}</font>
113-
Blood 2 : <font color='red'>{{blood_2}}</font>
114-
<button type="button" data-ng-click="fight()">Fight</button>
115-
<button type="button" data-ng-click="stopFight()">StopFight</button>
116-
<button type="button" data-ng-click="resetFight()">resetFight</button>
117-
</div>
118-
</div>
119-
120-
</doc:source>
121-
</doc:example>
12235
*/
12336
function timeout(fn, delay, invokeApply) {
12437
var deferred = $q.defer(),

0 commit comments

Comments
 (0)