var app = angular.module('quizApp', []);
app.directive('timer', function($timeout, $compile) {
return {
restrict: 'E',
replace: false,
scope: {
interval: '=interval',
startTimeAttr: '=startTime',
countdownattr: '=countdown'
},
controller: function($scope, $element) {
if ($element.html().trim().length === 0) {
$element.append($compile('<span>{{millis}}</span>')($scope));
}
$scope.startTime = null;
$scope.timeoutId = null;
$scope.countdown = $scope.countdownattr && parseInt($scope.countdownattr, 10) > 0 ? parseInt($scope.countdownattr, 10) : undefined;
$scope.isRunning = false;
$scope.$on('timer-start', function() {
$scope.start();
});
$scope.$on('timer-resume', function() {
$scope.resume();
});
$scope.$on('timer-stop', function() {
$scope.stop();
});
function resetTimeout() {
if ($scope.timeoutId) {
clearTimeout($scope.timeoutId);
}
}
$scope.start = $element[0].start = function() {
$scope.startTime = $scope.startTimeAttr ? new Date($scope.startTimeAttr) : new Date();
resetTimeout();
tick();
};
$scope.resume = $element[0].resume = function() {
resetTimeout();
$scope.startTime = new Date() - ($scope.stoppedTime - $scope.startTime);
tick();
};
$scope.stop = $element[0].stop = function() {
$scope.stoppedTime = new Date();
resetTimeout();
$scope.timeoutId = null;
};
$element.bind('$destroy', function() {
resetTimeout();
});
var tick = function() {
if ($scope.countdown > 0) {
$scope.countdown--;
} else if ($scope.countdown <= 0) {
$scope.stop();
}
$scope.millis = new Date() - $scope.startTime;
if ($scope.countdown > 0) {
$scope.millis = $scope.countdown * 1000
}
$scope.seconds = Math.floor(($scope.millis / 1000) % 60);
$scope.minutes = Math.floor((($scope.millis / (1000 * 60)) % 60));
$scope.hours = Math.floor((($scope.millis / (1000 * 60 * 60)) % 24));
$scope.days = Math.floor((($scope.millis / (1000 * 60 * 60)) / 24));
//We are not using $timeout for a reason. Please read here - https://github.com/siddii/angular-timer/pull/5
console.log($scope.seconds)
$scope.timeoutId = setTimeout(function() {
tick();
$scope.$apply();
}, $scope.interval);
$scope.$emit('timer-tick', {
timeoutId: $scope.timeoutId,
millis: $scope.millis
});
};
$scope.start();
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="quizApp">
<timer interval="1000">Time ends in : {{hours}} hours, {{minutes}} minutes, {{seconds}} seconds</timer>
</div>
I have this timer directive and got some issues listed below. Couldn't able to figure it out. Any help would be appreciated.
1) hours, minutes and seconds are not getting updated in markup.
2) timer is in increasing order. I want it in decreasing order.
I'm using this timer in my quiz app. So let's say total time is 1 hr 54mins 00sec. On starting quiz timer should start decreasing by seconds and then minutes and then hours. When it becomes 0, I should get an alert.
Thank you in advance.
A few issues I see:
var app = angular.module('app', []);
app.directive('timer', function($timeout, $compile) {
return {
restrict: 'E',
scope: {
interval: '=', //don't need to write word again, if property name matches HTML attribute name
startTimeAttr: '=?startTime', //a question mark makes it optional
countdownAttr: '=?countdown' //what unit?
},
template: '<div><p>'+
'<p>Time ends in : {{ hours }} hour<span data-ng-show="hours > 1">s</span>, ' +
'{{ minutes }} minutes, ' +
'{{ seconds }} seconds ' +
'<span data-ng-if="millis">, milliseconds: {{millis}}</span></p>' +
'<p>Interval ID: {{ intervalId }}<br>' +
'Start Time: {{ startTime | date:"mediumTime" }}<br>' +
'Stopped Time: {{ stoppedTime || "Not stopped" }}</p>' +
'</p>' +
'<button data-ng-click="resume()" data-ng-disabled="!stoppedTime">Resume</button>' +
'<button data-ng-click="stop()" data-ng-disabled="stoppedTime">Stop</button>',
link: function (scope, elem, attrs) {
//Properties
scope.startTime = scope.startTimeAttr ? new Date(scope.startTimeAttr) : new Date();
var countdown = (scope.countdownAttr && parseInt(scope.countdownAttr, 10) > 0) ? parseInt(scope.countdownAttr, 10) : 60; //defaults to 60 seconds
function tick () {
//How many milliseconds have passed: current time - start time
scope.millis = new Date() - scope.startTime;
if (countdown > 0) {
scope.millis = countdown * 1000;
countdown--;
} else if (countdown <= 0) {
scope.stop();
console.log('Your time is up!');
}
scope.seconds = Math.floor((scope.millis / 1000) % 60);
scope.minutes = Math.floor(((scope.millis / (1000 * 60)) % 60));
scope.hours = Math.floor(((scope.millis / (1000 * 60 * 60)) % 24));
scope.days = Math.floor(((scope.millis / (1000 * 60 * 60)) / 24));
//is this necessary? is there another piece of unposted code using this?
scope.$emit('timer-tick', {
intervalId: scope.intervalId,
millis: scope.millis
});
scope.$apply();
}
function resetInterval () {
if (scope.intervalId) {
clearInterval(scope.intervalId);
scope.intervalId = null;
}
}
scope.stop = function () {
scope.stoppedTime = new Date();
resetInterval();
}
//if not used anywhere, make it a regular function so you don't pollute the scope
function start () {
resetInterval();
scope.intervalId = setInterval(tick, scope.interval);
}
scope.resume = function () {
scope.stoppedTime = null;
scope.startTime = new Date() - (scope.stoppedTime - scope.startTime);
start();
}
start(); //start timer automatically
//Watches
scope.$on('time-start', function () {
start();
});
scope.$on('timer-resume', function() {
scope.resume();
});
scope.$on('timer-stop', function() {
scope.stop();
});
//Cleanup
elem.on('$destroy', function () {
resetInterval();
});
}
};
});
<!DOCTYPE html>
<html data-ng-app="app">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<timer interval="1000" countdown="61"></timer>
</body>
</html>
Or working JSBin here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With