Getting different values from a span - javascript

I want to create a website with multiple countdowns activated by a click, some of them have different time, others the same. When one finish I need to return it to his original countdown value, so you will be able to click it again.
I have the times (in seconds) inside a span .time, and that's how I get the time for the countdowns, however I don't know how to save the original time, so when one is clicked I get as "original time" always the first span .time.
Here is my code: http://jsfiddle.net/arglab/m19aojmu/16/
Javascript
function timer(selector) {
var description = ["seconds","hour"]
var self = $(selector);
var sec = parseInt(self.find('span.timeout').text());
console.log(sec)
order++;
var actualTime = $('span.timeout').html();
console.log("Original time " + actualTime)
self.addClass('selec').css('order',order+'');
var interval = setInterval(function() {
sec--;
console.log(sec)
if (sec >= 0) {
var hours = Math.floor(sec / 3600);
var min = Math.floor((sec - (hours*3600)) / 60);
var seconds = Math.floor(sec % 60);
var value = seconds;
if(min > 0) {
if(min == 1) {
value = " minute " + value;
} else {
value = " minutes " + value;
}
value = min + value;
}
if(hours > 0) {
if(hours == 1) {
value = " hour " + value;
} else {
value = " hours " + value;
}
value = hours + value;
}
self.find('span.timeout').text(value);
self.find('span.timeout').text(value);
} else if($(this).find('span').text() <= 0) {
console.log(sec)
var text = self.find('span.timeout').text(actualTime);
console.log(actualTime)
clearInterval(interval);
}
$('.element').each(function(){
if($(this).find('span').text() == 0){
$(this).removeClass('selec');
$(this).css('order','0');
}
});
}, 1000);
}
var order = 1;
$("body").on('click', '.element', function() {
timer(this);
});
HTML
<div id="container">
<div class="element" id="el1"><b>element 1</b> <span class="timeout">1000</span> seconds (1000)</div>
<div class="element" id="el2"><b>element 2</b> <span class="timeout">5</span> seconds (5)</div>
<div class="element" id="el3"><b>element 3</b> <span class="timeout">10</span> seconds (10)</div>
<div class="element" id="el4"><b>element 4</b> <span class="timeout">15</span> seconds (15)</div>
<div class="element" id="el5"><b>element 5</b> <span class="timeout">10</span> seconds (10)</div>
</div>
As you can see, if you click a 10 seconds countdown, when it finish his time isn't 10 seconds (as it should be) but, in this case, 1000 (first span .time)
What can I do? Thanks

You need to use self in your timer function.
Find the comments in the below code,
function timer(selector) {
var description = ["seconds", "hour"]
var self = $(selector);
var sec = parseInt(self.find('span.timeout').text());
console.log(sec)
order++;
var actualTime = self.find('span.timeout').html(); // use self.find here
console.log("Original time " + actualTime)
self.addClass('selec').css('order', order + '');
var interval = setInterval(function () {
sec--;
console.log(sec)
if (sec >= 0) {
var hours = Math.floor(sec / 3600);
var min = Math.floor((sec - (hours * 3600)) / 60);
var seconds = Math.floor(sec % 60);
var value = seconds;
if (min > 0) {
if (min == 1) {
value = " minute " + value;
} else {
value = " minutes " + value;
}
value = min + value;
}
if (hours > 0) {
if (hours == 1) {
value = " hour " + value;
} else {
value = " hours " + value;
}
value = hours + value;
}
self.find('span.timeout').text(value);
// remove the below redundant line
//self.find('span.timeout').text(value);
} else if (self.find('span').text() <= 0) { //use self not this
console.log(sec);
var text = self.find('span.timeout').text(actualTime);
console.log(actualTime)
clearInterval(interval);
}
$('.element').each(function () {
if ($(this).find('span').text() == 0) {
$(this).removeClass('selec');
$(this).css('order', '0');
}
});
}, 1000);
}
Live Demo

When registereing your onclick handler, you should pass another object to the timer function:
$("body").on('click', '.element', function(eve) {
timer(eve.target);
});

Related

Why does enabling timer to auto start disable my stop and reset buttons?

Thanks for any help here, not sure what's going on - but when I enable the timer(); line in order to automatically start the timer when the page is loaded, it disables the stop and reset buttons. I tried to only include relevant code here. Can anyone shed some light on why this is happening? Thank you in advance!
const startstop = () => {};
var clicks = 0;
function onClick() {
clicks += 1;
document.getElementById("clicks").innerHTML = clicks;
};
const input = parseInt(prompt("Enter a SAMS number: "));
var SAMSINPUT = input;
//console.log(SAMSINPUT);
document.getElementById('output').innerHTML = SAMSINPUT;
var goal = 0;
//var SAMSINPUTtest = parseInt(document.getElementById("input"));
//setInterval(function doIncrement() {
// goal += 1;
//}, SAMSINPUT * 1000); // *1000 to convert from seconds to milliseconds
var output2 = document.getElementById('output2');
setInterval(function doIncrement() {
goal += 1;
output2.innerHTML = goal.toString();
}, SAMSINPUT * 1000)
var timerDiv = document.getElementById('timerValue'),
start = document.getElementById('start'),
stop = document.getElementById('stop'),
reset = document.getElementById('reset'),
t;
// Get time from cookie
var cookieTime = null; //getCookie('time'); // for test
// If timer value is saved in the cookie
if (cookieTime != null && cookieTime != '00:00:00') {
var savedCookie = cookieTime;
var initialSegments = savedCookie.split('|');
var savedTimer = initialSegments[0];
var timerSegments = savedTimer.split(':');
var seconds = parseInt(timerSegments[2]),
minutes = parseInt(timerSegments[1]),
hours = parseInt(timerSegments[0]);
timer();
document.getElementById('timerValue').textContent = savedTimer;
$('#stop').removeAttr('disabled');
$('#reset').removeAttr('disabled');
} else {
var seconds = 0,
minutes = 0,
hours = 0;
timerDiv.textContent = "00:00:00";
}
// New Date object for the expire time
var curdate = new Date();
var exp = new Date();
// Set the expire time
exp.setTime(exp + 2592000000);
function add() {
seconds++;
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
}
}
timerDiv.textContent = (hours ? (hours > 9 ? hours : "0" + hours) : "00") +
":" + (minutes ? (minutes > 9 ? minutes : "0" + minutes) : "00") +
":" + (seconds > 9 ? seconds : "0" + seconds);
// Set a 'time' cookie with the current timer time and expire time object.
var timerTime = timerDiv.textContent.replace("%3A", ":");
//console.log('timerTime', timerTime);
//setCookie('time', timerTime + '|' + curdate, exp);
timer();
}
function timer() {
t = setTimeout(add, 1000);
}
timer(); // autostart timer
/* Start button */
start.onclick = timer;
/* Stop button */
stop.onclick = function() {
clearTimeout(t);
}
/* Clear button */
reset.onclick = function() {
timerDiv.textContent = "00:00:00";
seconds = 0;
minutes = 0;
hours = 0;
//setCookie('time', "00:00:00", exp);
}
/**
* Javascript Stopwatch: Button Functionality
*
*/
$('#start').on('click', function() {
$('#stop').removeAttr('disabled');
$('#reset').removeAttr('disabled');
});
$('#stop').on('click', function() {
$(this).prop('disabled', 'disabled');
});
$('#reset').on('click', function() {
$(this).prop('disabled', 'disabled');
});
/**
* Javascript Stopwatch: Cookie Functionality
*
*/
function setCookie(name, value, expires) {
document.cookie = name + "=" + value + "; path=/" + ((expires == null) ? "" : "; expires=" + expires.toGMTString());
}
function getCookie(name) {
var cname = name + "=";
var dc = document.cookie;
if (dc.length > 0) {
begin = dc.indexOf(cname);
if (begin != -1) {
begin += cname.length;
end = dc.indexOf(";", begin);
if (end == -1) end = dc.length;
return unescape(dc.substring(begin, end));
}
}
return null;
}
body {
background-color: powderblue;
}
p {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body onload="startstop();">
<p> SAMS VALUE:
<a id="output"></a>
</p>
<p> GOAL:
<a id="output2"></a>
</p>
<button style="background-color:green" type="button" onClick="onClick()">ACTUAL</button>
<p>Actual Count: <a id="clicks">0</a></p>
<div class="container">
<div class="row">
<div class="col-sm-4"></div>
<div class="col-sm-4">
<div id="timeContainer" class="well well-sm">
<time id="timerValue"></time>
</div>
<div id="timerButtons">
<button id="start" class="btn btn-success">START</button>
<button id="stop" class="btn btn-danger" disabled="disabled">STOP</button>
<button id="reset" class="btn btn-default" disabled="disabled">RESET</button>
</div>
<div class="col-sm-4 col-sm-4 col-md-4"></div>
</div>
</div>
</div>
</body>

How can I modify my function to be able to cancel the interval from anywhere in the controller

I am trying to create a countdown and I want to be able to cancel the interval not only when reach 0 but with clicking of a button as well.How can I modify my function to be able to cancel the interval from anywhere in the controller.
function countDown(total) {
total = total * 60;
var interval = $interval(function () {
var minutes = Math.floor(total / 60);
var seconds = total - minutes * 60;
if (minutes < 1)
{
minutes = '0:';
}
else
{
minutes = minutes + ':';
}
if (seconds < 10)
{
seconds = '0' + seconds;
}
self.remainingTime = "Remaining time: " + minutes + seconds;
total--;
if(minutes === '0:' && seconds === '00')
{
$interval.cancel(interval);
}
}, 1000);
}
As suggested by other users, you should make interval global in the controller. Then on the other functions you want to cancel the interval you can call it safely.
Take a look at the below sample:
angular.module('app', [])
.controller('ctrl', function($interval) {
var self = this;
var interval;
self.wizard = {
startInterval: startInterval,
cancelInterval: cancelInterval
};
startInterval();
return self.wizard;
function startInterval() {
countDown(24);
}
function cancelInterval() {
$interval.cancel(interval);
}
function countDown(total) {
cancelInterval();
total = total * 60;
interval = $interval(function() {
var minutes = Math.floor(total / 60);
var seconds = total - minutes * 60;
if (minutes < 1) {
minutes = '0:';
} else {
minutes = minutes + ':';
}
if (seconds < 10) {
seconds = '0' + seconds;
}
self.wizard.remainingTime = "Remaining time: " + minutes + seconds;
total--;
if (minutes === '0:' && seconds === '00') {
$interval.cancel(interval);
}
}, 1000);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<span ng-app="app" ng-controller="ctrl as ctrl">
<span ng-bind="ctrl.remainingTime"> </span>
<br/>
Cancel Interval
<br/>
Start Interval
</span>
I created an example using self instead of $scope like you are in your snippet above. As others mentioned moving the interval var to the global scope fixes this. I also added a stop and start function to test the issue you mentioned in the example above.
UPDATED - I added some code to the stop interval to reset the interval to undefined. I found an example of this usage on Angular's site so it might be worth a try to see if it fixes your other issue.
var app = angular.module('app', []);
app.controller('BaseController', function($interval) {
var self = this;
var interval;
function countDown(total) {
total = total * 60;
interval = $interval(function() {
var minutes = Math.floor(total / 60);
var seconds = total - minutes * 60;
if (minutes < 1) {
minutes = '0:';
} else {
minutes = minutes + ':';
}
if (seconds < 10) {
seconds = '0' + seconds;
}
self.remainingTime = "Remaining time: " + minutes + seconds;
total--;
if (minutes === '0:' && seconds === '00') {
$interval.cancel(interval);
}
}, 1000);
}
self.stopInterval = function(){
if (angular.isDefined(interval)) {
$interval.cancel(interval);
interval = undefined;
}
}
self.startInterval = function(){
countDown(10);
}
});
Then in the html I added a button to start and stop the interval like so:
<body ng-app="app">
<div ng-controller="BaseController as baseCtrl">
{{ baseCtrl.remainingTime }}
<div>
<button ng-click="baseCtrl.startInterval()">Start Countdown</button>
<button ng-click="baseCtrl.stopInterval()">Stop Countdown</button>
</div>
</div>
</body>
You can view the codepen example here

how to set the same id for multiple element in html

I want to use countdown timer for 10 element that creating at run time. each element has expire time so I want to show user how much time of of the expiration is remained.so I use a jquery file to do this .so I must use an id for a tag to show the remained time .when I use it for one element it works fine but when I use it for multiple element it just works for first element.how can I solve this problem to show the remained time for all elements
Jquery file
//var count = 1000;
//var counter = setInterval(timer, 1000);
//function timer() {
// count -= 1;
// if (count==1000) {
// clearInterval(counter);
// }
// document.getElementById("num").innerHTML = count;
//}
function CountDown() {
this.start_time = "02:00:00:23";
this.target_id = "#timer";
this.name = "timer";
}
CountDown.prototype.init=function(){
this.reset();
setInterval(this.name+'.tick()',1000);
}
CountDown.prototype.reset=function(){
time = this.start_time.split(":");
this.days = parseInt(time[0]);
this.hours = parseInt(time[1]);
this.minutes=parseInt(time[2]);
this.seconds = parseInt(time[3]);
this.update_target();
}
CountDown.prototype.tick=function(){
if (this.seconds > 0 || this.minutes > 0 || this.hours > 0 ||this.days>0) {
if (this.hours == 0 && this.minutes == 0 && this.seconds == 0) {
this.days = this.days - 1;
this.hours = 23;
this.minutes = 59;
this.seconds = 59;
}
if (this.minutes == 0 && this.seconds==0) {
this.hours = this.hours - 1;
this.minutes = 59;
this.seconds = 59;
}
else if (this.seconds == 0) {
this.minutes = this.minutes - 1;
this.seconds = 59;
}
else {
this.seconds = this.seconds - 1;
}
}
this.update_target();
}
CountDown.prototype.update_target = function () {
seconds = this.seconds;
minutes = this.minutes;
hours = this.hours;
days = this.days;
if (seconds<10)
seconds = "0"+seconds;
if (minutes < 10)
minutes = "0"+ minutes;
if (hours < 10)
hours = "0" + hours;
if (days < 10)
days = "0" + days;
$(this.target_id).val(days+":"+hours+":"+minutes + ":" + seconds)
// $(this.target_id).val(this.minutes+":"+seconds)
}
Html
<script src="~/Scripts/jquery-1.4.4.min.js"></script>
<script src="~/Scripts/countdown.js"></script>
<input type="text" id="timer" value=" " />
<script>
timer = new CountDown();
timer.init();
</script>
Id is unique in html use class instead .. more element can have the same class
$('.yourClass')
instead of
$('#yourId')
.
<script src="~/Scripts/jquery-1.4.4.min.js"></script>
<script src="~/Scripts/countdown.js"></script>
<input type="text" class="timer" value=" " />
<script>
timer = new CountDown();
timer.init();
</script>
function CountDown() {
this.start_time = "02:00:00:23";
this.target_id = ".timer";
this.name = "timer";
}
EDIT :
I've created a JSFiddle for it, can you precise your request ?
See it here
I changed this :
timer = new CountDown("02:00:00:23");
timer.init();
And this function :
function CountDown(start_time) {
this.start_time = start_time;
this.target_id = ".timer";
this.name = "timer";
}
Id's are unique and should only be used once in an html page. Also, and element should only have a single ID. Classes are not unique so multiple elements can have the same class, also, a single element can have multiple classes. Example:
<div class="exampleClass anotherClass"></div>
<div class="exampleClass></div>
<div class="exampleClass></div>
Instead of id="timer" use class="timer" then in your javascript file use $(".timer") to target those classes. So in your case instead of this.target_id = "#timer" use this.target_id =".timer";
Here's a good reference for classes and ids.

Failed to start countdown for the second time during operation

I am using the following code and giving a second click to the same start countdown button not clean the first process, so there are two counts at the same time. How do I stop the first process when the second start?
Thank you very much in advance.
function countdown(element, minutes, seconds) {
// Fetch the display element
var el = document.getElementById(element);
// Set the timer
var interval = setInterval(function() {
if(seconds == 0) {
if(minutes == 0) {
(el.innerHTML = "STOP!");
clearInterval(interval);
return;
} else {
minutes--;
seconds = 60;
}
}
if(minutes > 0) {
var minute_text = minutes + (minutes > 1 ? ' minutes' : ' minute');
} else {
var minute_text = '';
}
var second_text = seconds > 1 ? '' : '';
el.innerHTML = minute_text + ' ' + seconds + ' ' + second_text + '';
seconds--;
}, 1000);
}
//Start as many timers as you want
var start1 = document.getElementById('timer1');
var start2 = document.getElementById('timer2');
start1.onclick = function() {
countdown('countdown1', 0, 15);
}
start2.onclick = function() {
countdown('countdown2', 0, 10);
}
//extra button and counter
<div id='countdown1'></div>
<div id='countdown2'></div>
<input id="timer1" type="button" value="Start timer 1" />
<input id="timer2" type="button" value="Start timer 2" />
You could save the interval variable as an attribute of the countdown element. Then, at the beginning of the countdown function, check if the interval attribute has been defined for that element. If so, call clearInterval on it before starting a new interval.
clearInterval(intervalvalue)
will be helpful to .
Working code here

jquery event delegation won't work

So I have this code.
$("#inputs input.time").mask("00:00:00");
$("#inputs input.time").prop('value', '00:00:00');
Number.prototype.padDigit = function () {
return (this < 10) ? '0' + this : this;
}
$('#display').click(function () {
$('#show').show();
});
$('#inputs').on('focus', 'input.time', function () {
$(this).select();
});
$('#append').click(function () {
$('#inputs').after("<input type='text' value='00:00:00' class='time' name='time2' /><br>");
});
$('#inputs').on('keyup', 'input.time', function (event) {
console.log(event);
var t1 = '00:00:00';
var mins = 0;
var hrs = 0;
var sec = 0;
$('#inputs input.time').each(function () {
t1 = t1.split(':');
var t2 = $(this).val().split(':');
//console.log(Number(t1[1]) + Number(t2[1]))
sec = Number(t1[2]) + Number(t2[2]);
secmns = Math.floor(parseInt(sec / 60));
mins = Number(t1[1]) + Number(t2[1]) + secmns;
minhrs = Math.floor(parseInt(mins / 60));
hrs = Number(t1[0]) + Number(t2[0]) + minhrs;
sec = sec % 60;
mins = mins % 60;
t1 = hrs.padDigit() + ':' + mins.padDigit() + ':' + sec.padDigit()
console.log(t1)
});
if (t1 == 'NaN:NaN:NaN') {
t1 = '00:00:00';
}
$('#total').text(t1);
/*****************subtract time*****************/
//new Date(year, month, day, hours, minutes, seconds, milliseconds)
//problem, if the seconds, mins or hrs of total is bigger than the remaining. Unexpected result
var start = $('#rem').text();
var end = $('#total').text();
s = start.split(':');
e = end.split(':');
var se = Number(s[2]) - Number(e[2]);
var sems = Math.floor(parseInt(sec / 60));
var mi = Number(s[1]) - Number(e[1]) - sems;
var mihr = Math.floor(parseInt(mins / 60));
var hr = Number(s[0]) - Number(e[0]) - mihr;
if (se < 0) {
mi = mi - 1;
se = se + 60;
}
if (mi < 0) {
hr = hr - 1;
mi = mi + 60;
}
var result = hr.padDigit() + ':' + mi.padDigit() + ':' + se.padDigit();
if (result == 'NaN:NaN:' + se) {
result = '00:00:00';
}
$('#remain').text(result);
});
#remain,
#total {
background-color: #333;
width: 60px;
height: 20px;
color: #fff;
padding: 0 10px;
}
#show {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<script src="https://raw.githubusercontent.com/igorescobar/jQuery-Mask-Plugin/master/src/jquery.mask.js"></script>
<button id='display'>Display</button>
<div id='show'>Remaining:
<div id='remain'>01:20:30</div>Total:
<div id='total'>00:00:00</div>
<div id='rem'>01:20:30</div>
<br>
<div id='inputs'>
<input type='text' class='time' />
<button id='append'>+</button>
<br>
</div>
</div>
my problem is that the event on('keyup') works fine with .append and the result run on keyup event but if i use.after instead of .append, the code still works but the result will only show if the keyup event is done on the very first input. if the code above won't run, try my JFiddle . It's just the same code as above.
Hope this is what you want!! You need to use insertAfter and insert it after last input in the #inputs div
$('#append').click(function () {
$("<input type='text' value='00:00:00' class='time' name='time2' />").insertAfter("#inputs input:last");
});
Here is the working DEMO
EDIT - 2
Change as below and it will work:
$('#append').click(function () {
$("#inputs").after("<input type='text' value='00:00:00' class='time' name='time2' /><br/>");
});
$(document).on('keyup', 'input.time', function (event) {
console.log(event);
var t1 = '00:00:00';
var mins = 0;
var hrs = 0;
var sec = 0;
$('input.time').each(function () {
t1 = t1.split(':');
var t2 = $(this).val().split(':');
//console.log(Number(t1[1]) + Number(t2[1]))
sec = Number(t1[2]) + Number(t2[2]);
secmns = Math.floor(parseInt(sec / 60));
mins = Number(t1[1]) + Number(t2[1]) + secmns;
minhrs = Math.floor(parseInt(mins / 60));
hrs = Number(t1[0]) + Number(t2[0]) + minhrs;
sec = sec % 60;
mins = mins % 60;
t1 = hrs.padDigit() + ':' + mins.padDigit() + ':' + sec.padDigit()
console.log(t1)
});
if (t1 == 'NaN:NaN:NaN') {
t1 = '00:00:00';
}
$('#total').text(t1);
/*****************subtract time*****************/
//new Date(year, month, day, hours, minutes, seconds, milliseconds)
//problem, if the seconds, mins or hrs of total is bigger than the remaining. Unexpected result
var start = $('#rem').text();
var end = $('#total').text();
s = start.split(':');
e = end.split(':');
var se = Number(s[2]) - Number(e[2]);
var sems = Math.floor(parseInt(sec / 60));
var mi = Number(s[1]) - Number(e[1]) - sems;
var mihr = Math.floor(parseInt(mins / 60));
var hr = Number(s[0]) - Number(e[0]) - mihr;
if (se < 0) {
mi = mi - 1;
se = se + 60;
}
if (mi < 0) {
hr = hr - 1;
mi = mi + 60;
}
var result = hr.padDigit() + ':' + mi.padDigit() + ':' + se.padDigit();
if (result == 'NaN:NaN:' + se) {
result = '00:00:00';
}
$('#remain').text(result);
});
WORKING DEMO
Basically what you are trying to do is you are inserting the inputs
after the #inputs div and you have written code to accept keyup
which are present inside #inputs div. Since you are giving same
class name to all the inputs where you make changes if you refer
only them it is enough. No need to reach them through their parent
div.

Categories

Resources