Skip to content

Commit e7ecf43

Browse files
committed
Add timer demo.
1 parent 70c97b5 commit e7ecf43

File tree

4 files changed

+453
-0
lines changed

4 files changed

+453
-0
lines changed
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
a[ ng-click ] {
3+
cursor: pointer ;
4+
text-decoration: underline ;
5+
}
+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
<!doctype html>
2+
<html ng-app="Demo">
3+
<head>
4+
<meta charset="utf-8" />
5+
6+
<title>
7+
Creating A Reusable Timer In AngularJS
8+
</title>
9+
10+
<link rel="stylesheet" type="text/css" href="./demo.css"></link>
11+
</head>
12+
<body ng-controller="AppController">
13+
14+
<h1>
15+
Creating A Reusable Timer In AngularJS
16+
</h1>
17+
18+
<p>
19+
<a ng-click="handleClick()">Click me</a> to star the timer!
20+
</p>
21+
22+
<p ng-if="logExecutedAt">
23+
Executed: {{ logExecutedAt.getTime() }}
24+
</p>
25+
26+
27+
<!-- Load scripts. -->
28+
<script type="text/javascript" src="../../vendor/jquery/jquery-2.1.0.min.js"></script>
29+
<script type="text/javascript" src="../../vendor/angularjs/angular-1.2.22.min.js"></script>
30+
<script type="text/javascript">
31+
32+
// Create an application module for our demo.
33+
var app = angular.module( "Demo", [] );
34+
35+
36+
// -------------------------------------------------- //
37+
// -------------------------------------------------- //
38+
39+
40+
// I control the root of the application.
41+
app.controller(
42+
"AppController",
43+
function( $scope, timer ) {
44+
45+
// I am a timer that will invoke the given callback once the timer has
46+
// finished. The timer can be reset at any time.
47+
// --
48+
// NOTE: Is a thin wrapper around $timeout() which will trigger a $digest
49+
// when the callback is invoked.
50+
var logClickTimer = timer( logClick, timer.TWO_SECONDS );
51+
52+
$scope.logExecutedAt = null;
53+
54+
// When the current scope is destroyed, we want to make sure to stop
55+
// the current timer (if it's still running). And, give it a chance to
56+
// clean up its own internal memory structures.
57+
$scope.$on(
58+
"$destroy",
59+
function() {
60+
61+
logClickTimer.teardown();
62+
63+
}
64+
);
65+
66+
67+
// ---
68+
// PUBLIC METHODS.
69+
// ---
70+
71+
72+
// I handle the click event. Instead of logging the click right away,
73+
// we're going to throttle the click through a timer.
74+
$scope.handleClick = function() {
75+
76+
$scope.logExecutedAt = null;
77+
78+
logClickTimer.restart();
79+
80+
};
81+
82+
83+
// ---
84+
// PRIVATE METHODS.
85+
// ---
86+
87+
88+
// I log the fact that the click happened at this point in time.
89+
function logClick() {
90+
91+
$scope.logExecutedAt = new Date();
92+
93+
}
94+
95+
}
96+
);
97+
98+
99+
// -------------------------------------------------- //
100+
// -------------------------------------------------- //
101+
102+
103+
// I create timers that wrap the $timeout and provide easy ways to cancel and
104+
// reset the timer.
105+
app.factory(
106+
"timer",
107+
function( $timeout ) {
108+
109+
// I provide a simple wrapper around the core $timeout that allows for
110+
// the timer to be easily reset.
111+
function Timer( callback, duration, invokeApply ) {
112+
113+
// Store properties.
114+
this._callback = callback;
115+
this._duration = ( duration || 0 );
116+
this._invokeApply = ( invokeApply !== false );
117+
118+
// I hold the $timeout promise. This will only be non-null when the
119+
// timer is actively counting down to callback invocation.
120+
this._timer = null;
121+
122+
}
123+
124+
// Define the instance methods.
125+
Timer.prototype = {
126+
127+
// Set constructor to help with instanceof operations.
128+
constructor: Timer,
129+
130+
131+
// I determine if the timer is currently counting down.
132+
isActive: function() {
133+
134+
return( !! this._timer );
135+
136+
},
137+
138+
139+
// I stop (if it is running) and then start the timer again.
140+
restart: function() {
141+
142+
this.stop();
143+
this.start();
144+
145+
},
146+
147+
148+
// I start the timer, which will invoke the callback upon timeout.
149+
start: function() {
150+
151+
var self = this;
152+
153+
// NOTE: Instead of passing the callback directly to the timeout,
154+
// we're going to wrap it in an anonymous function so we can set
155+
// the enable flag. We need to do this approach, rather than
156+
// binding to the .then() event since the .then() will initiate a
157+
// digest, which the user may not want.
158+
this._timer = $timeout(
159+
function handleTimeoutResolve() {
160+
161+
try {
162+
self._callback.call( null );
163+
} finally {
164+
self = self._timer = null;
165+
}
166+
167+
},
168+
this._duration,
169+
this._invokeApply
170+
);
171+
172+
},
173+
174+
175+
// I stop the current timer, if it is running, which will prevent the
176+
// callback from being invoked.
177+
stop: function() {
178+
179+
$timeout.cancel( this._timer );
180+
181+
this._timer = false;
182+
183+
},
184+
185+
186+
// I clean up the internal object references to help garbage
187+
// collection (hopefully).
188+
teardown: function() {
189+
190+
this.stop();
191+
this._callback = null;
192+
this._duration = null;
193+
this._invokeApply = null;
194+
this._timer = null;
195+
196+
}
197+
198+
};
199+
200+
201+
// Create a factory that will call the constructor. This will simplify
202+
// the calling context.
203+
function timerFactory( callback, duration, invokeApply ) {
204+
205+
return( new Timer( callback, duration, invokeApply ) );
206+
207+
}
208+
209+
// Store the actual constructor as a factory property so that it is still
210+
// accessible if anyone wants to use it directly.
211+
timerFactory.Timer = Timer;
212+
213+
// Set up some time-based constants to help readability of code.
214+
timerFactory.ONE_SECOND = ( 1 * 1000 );
215+
timerFactory.TWO_SECONDS = ( 2 * 1000 );
216+
timerFactory.THREE_SECONDS = ( 3 * 1000 );
217+
timerFactory.FOUR_SECONDS = ( 4 * 1000 );
218+
timerFactory.FIVE_SECONDS = ( 5 * 1000 );
219+
220+
221+
// Return the factory.
222+
return( timerFactory );
223+
224+
}
225+
);
226+
227+
</script>
228+
229+
</body>
230+
</html>

index.htm

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ <h1>
1313
</h1>
1414

1515
<ul>
16+
<li>
17+
<a href="./demos/reusable-timer-angularjs/">Creating A Reusable Timer In AngularJS</a>
18+
</li>
1619
<li>
1720
<a href="./demos/nested-event-timing-angularjs/">Looking At Nested Event Timing And DOM Structure In AngularJS</a>
1821
</li>

0 commit comments

Comments
 (0)