setInterval keeps stacking even with clearInterval - javascript

I'm making a simple punch in / punch out timer.
Problem im facing is that it works perfectly on page load but when the user clicks end_work_btn then begin_work_btn, the timer kinda stacks the initial value and the new one starting from 0 so it's trying to display both. It keeps stacking everytime they click the buttons until page reload when it resets.
I've done a bunch of reading and figured clearInterval(timer) would do it but no go so assuming i'm not using it correctly or i'm way off the ball on whats wrong here.
Here's what I got so far
<button id="begin_work_btn">Begin Work</button>
<button id="end_work_btn"><span id="hours"></span>:<span id="minutes"></span>:<span id="seconds"></span></button>
<script>
var emp_id = '2';
var timer = null;
function reset_timer(time){
var sec = time;
clearInterval(timer);
function pad ( val ) {
return val > 9 ? val : "0" + val;
}
var timer = setInterval( function(){
$("#seconds").html(pad(++sec%60));
$("#minutes").html(pad(parseInt(sec/60,10)%60));
$("#hours").html(pad(parseInt(sec/3600,10)));
}, 1000);
}
reset_timer(<?php echo $existing_time;?>);
$("#begin_work_btn").click(function(){
$.ajax({
type: "post",
url: "<?php echo $url;?>process.php",
data: "agent_id="+emp_id+"&action=begin_work",
success: function(data){
var sec = 0;
reset_timer(sec);
$('#begin_work_btn').hide();
$('#end_work_btn').show();
}
});
});
$("#end_work_btn").click(function(){
$.ajax({
type: "post",
url: "<?php echo $url;?>process.php",
data: "agent_id="+emp_id+"&action=end_work",
success: function(data){
$('#end_work_btn').hide();
$('#begin_work_btn').show();
}
});
});
</script>

Pretty simple, scope is different. In your code you have two variables named timer. The one inside the function is created each time reset_timer is called. One outside never gets a value. So each time you call the function, another instance of timer is created.
var timer = null; //<-- outside
function reset_timer(time){
clearInterval(timer);
var timer = setInterval( ... , 1000); //<--redefined inside so each time, it creates new variable
}
You basically have this:
function reset_timer(time){
var timer;
clearInterval(timer);
timer = setInterval( ... , 1000);
}
It should not be defined with var. This way it updates the variable defined outside of the function each time it is called.
var timer = null;
function reset_timer(time){
if (timer) clearInterval(timer);
timer = setInterval( ... , 1000); //<--no more var
}

Related

How to make JavaScript countdown timer work again and again on clicking a button?

On clicking a button with id next-problem , an AJAX request is send to server and new task get loaded. I want to restart the timer when new task get loaded. In AJAX , on success I want to reset timer. But the problem is many setInterval get starts on click the button. How to avoid that ?
var timer;
var countdownfunction;
var countDownTime;
timer = function (){
clearInterval(countdownfunction);
countDownTime = $("#timer").attr("data-timer-val");
var countdownfunction = setInterval(function() {
if(countDownTime < 10 ){
var temp = "0" + countDownTime;
$("#time").text(temp);
}else{
$("#time").text(countDownTime);
}
countDownTime = countDownTime - 1;
if (countDownTime < 0) {
clearInterval(countdownfunction);
$("#time-expired").text("Please click next problem.");
}
}, 1000);
} ;
$(document).ready(function(){
timer();
});
$(document).ready(function(){
$("#next-problem").on('click', function(){
$.ajax({
type : 'POST',
url : '/test/next-problem/',
success : function(data){
// console.log(data);
$("#problem-content").html(data);
clearInterval(countdownfunction);
timer();
},
});
});
});
Remove var from the following line:
var countdownfunction = setInterval(function() {
Because of this var you have two differently scoped values of countdownfunction so when you call clearInterval you are never clearing this particular functionally-scoped value until that timer reaches -1, so you may have multiple timers running on top of each other.
Once you remove var here, you now have a single, globally-scoped variable that can be cleared and reassigned a value.

setInterval starts my page to lag when it generates 30 plus data

can anyone help me with my problem with setInterval because it starts to lagg like pause and resume thing happens in my page if it generate 30 plus more data in my static textboxes in my page. Does anyone know how to solve the lagg issue in my problem?
<script>
$(document).ready(function(){
var $funiq_id = $('#funiq_id'),
$t_region = $('#t_region'),
$t_town = $('#t_town'),
$t_uniq_id = $('#t_uniq_id'),
$t_position = $('#t_position'),
$t_salary_grade = $('#t_salary_grade'),
$t_salary = $('#t_salary');
var auto_refresh = setInterval(
function updateTextboxes(){
$.ajax({
url:"search.php",
type:"GET",
data: { term : $('#query').val() },
dataType:"JSON",
success: function(result) {
var ii = 1;
for (var i = 0; i < result.length; i++) {
$funiq_id.html(result[i].value).show();
$t_region.val(result[i].region).show().trigger('input');
$t_town.val(result[i].town).show().trigger('input');
$t_uniq_id.val(result[i].uniq_id).show().trigger('input');
$t_position.val(result[i].position).show().trigger('input');
$t_salary_grade.val(result[i].salary_grade).show().trigger('input');
$t_salary.val(result[i].salary).show().trigger('input');
$('#id'+ii+'').val(result[i].atid).show().trigger('input');
$('#aic'+ii+'').val(result[i].atic).show().trigger('input');
$('#name'+ii+'').val(result[i].atname).show().trigger('input');
$('#other_qual'+ii+'').val(result[i].other_sum).show().trigger('input');
$('#interview'+ii+'').val(result[i].interview_sum).show().trigger('input');
$('#optA'+ii+'').val(result[i].edu_attain2_sum).show().trigger('input');
$('#optB'+ii+'').val(result[i].experience2_sum).show().trigger('input');
$('#optC'+ii+'').val(result[i].trainings2_sum).show().trigger('input');
$('#optD'+ii+'').val(result[i].eligibility2_sum).show().trigger('input');
$('#total'+ii+'').val(result[i].final_total_sum).show().trigger('input');
$(':input').removeAttr('placeholder');
ii++;
}
}
});
},500);
$('.search_form_input').val('');
$('.search_textbox').val('');
$(".empty_batchcode").html("");
$('#execute').prop('disabled', true);
});
</script>
You are performing an asynchronous request every 500 milliseconds, so it is likely that they will start queueing up and your browser will not be able to complete them in time.
You could increase the interval, but you would be better off to remove setInterval and only do another request when it finishes i.e. inside your success function:
E.g.
success: function(result) {
...
//at the end of the function
updateTextboxes(); //or setTimeout(updateTextboxes, 500);
}
If you want to only call it after your input changes, then you can remove the setInterval/setTimeout altogether and just attach to the onblur or onkeydown events e.g.
<input id='search' type="text" onkeydown="updateTextboxes()">
or using jQuery
$('#search').change(updateTextboxes);

Javascript : Do Action after elapsed time

I have a page where I fire an ajax request AND show a loading sign for the first 6 seconds after the user presses a button :
<button onclick="runLoader();"></button>
<script>
var startTime=(new Date).getTime();
function runLoader(){
runAjax();
var i=0;
var timer = setInterval(function(e){
i++;
//code for loading sign
if(i==3)
clearInterval(timer);
} ,2000);
}
function runAjax(){
$.ajax({
//
}).done(function(){
var timer2 = setInterval(function(){
var d = new Date();
var t = d.getTime();
if(t-startTime>=6000){
clearInterval(timer2);
// do X
}
},500);
}
}
</script>
I want to do action X only after both runLoader() has run for 6 seconds and runAjax() has resulted in a response, and no sooner.
Like, if runAjax() responds in 2 seconds, I still want to continue showing loading sign for 6 seconds and then perform X.
And if the loading sign has shown for 6 seconds, I want to wait for runAjax() to return for as long as it takes.
But using the Date() method is giving inaccurate results. For eg : It shows 7.765 s elapsed even when only 2 s have passed. I read somewhere I should use console.log(time) for better accuracy, but it doesnt work in <=IE9.
Is there a better way to approach this problem ?
Note: I am using setInterval() instead of setTimeout() because the loading involves cycling through an array of 3 elements, "Fetching", "Processing" and "Loading" each shown for 2 seconds :)
I would use deferreds and $.when:
function start(){
$.when(runLoader(), runAjax()).done(function() {
//both are now finished
});
}
function runLoader() {
//show loader here
var def = $.Deferred();
setTimeout(function() {
//hide loader here
def.resolve(true);
}, 6000);
return def.promise();
}
function runAjax() {
var def = $.Deferred();
$.ajax({...}).done(function(result) {
//handle response here
def.resolve(true);
});
return def.promise();
}
I would set a flag to mark it as "ready". There may be better ways to handle this, but this is just off the top of my head.
<script>
function runLoader(){
runAjax();
var i=0;
var timer = setInterval(function(e){
i++;
//code for loading sign
if(i==3)
clearInterval(timer);
} ,2000);
}
function runAjax(){
var timeElapsed = false;
setTimeout(function(){timeElapsed = true}, 6000);
$.ajax({
//
}).done(function(){
var timer2 = setInterval(function(){
if(timeElapsed){
clearInterval(timer2);
// do X
}
},500);
}
}
</script>
You can create a pre-caller function that is run on runLoader() and as callback of runAjax(), that will verify if the other action is complete, and then do action X. Example:
var ajaxDone = false;
var loaderDone = false;
function doActionX() {
//your action happens here
}
function tryToDoX() {
if (ajaxDone && loaderDone) {
doActionX();
}
}
function runLoader(){
loaderDone = false;
runAjax();
//show loading sign
setInterval(function(e){
//hide loading sign
clearInterval(timer);
loaderDone = true;
tryToDoX();
}, 6000);
}
function runAjax(){
ajaxDone = false;
$.ajax({
//whatever
}).done(function(){
ajaxDone = true;
tryToDoX();
}
}
It isn't necessary to make a recurring timeout and poll both statuses, because they only get completed once (in every run, i.e. booleans aren't set to false and true while waiting).
EDIT: This approach can be used to any asynchronous code that doesn't change status intermitently, even without jQuery.

setInterval javascript calls do not go away after ajax load

I'm using MVC with some partial rendering and ajax calls. In one of my result tables I have a field that is a timer.
The following code is on my partial view that is rendered every 30 seconds. One of the fields is an active timer that displays to the user:
<td><div id="#someID" class="nobutton"></div><script>setInterval(function () { startTimer('#startDateTime', '#someID') }, 500);</script></td>
This works great but after the ajax call is made to refresh the partial, the interval function is still calling the old IDs (someID) that are no longer there.
Here is the javascript for the timer:
<script type="text/javascript">
function startTime(dt, field){
var field = document.getElementById(field);
if (field == null)
return;
var rowTime = new Date(dt);
var rowTimems = rowTime.getTime(rowTime);
var currentTime = new Date();
var currentTimems = currentTime.getTime(currentTime);
var difference = currentTimems - rowTimems;
var hours = Math.floor(difference / 36e5),
minutes = Math.floor(difference % 36e5 / 60000),
seconds = Math.floor(difference % 60000 / 1000);
field.innerHTML = formatTime(hours) + ":" + formatTime(minutes) + ":" + formatTime(seconds);
</script>
And the call on the main page that refreshes the partial is pretty simple:
var t = setInterval(function () {
$.ajax({
url: "MYURL",
type: "GET",
cache: false,
success: function (data) {
$("#summary").html(data);
}
});
}, 30000);
Is there a way to kill the old timers? Why are they still running?
The reason that code is still executing is that the interval was never stopped. Try this in your partial instead. It will check if the previous interval timer is present and clear it.
<td><div id="#someID" class="nobutton"></div>
<script>
if( window.prtInt != void 0 ) clearInterval(window.prtInt);//void 0 means undefined
window.prtInt = setInterval(function () { startTimer('#startDateTime', '#someID') }, 500);
</script></td>
If you wish to clear out all the timers on the entire page (may have undesirable affects) then you may get the integer for a new timer, and loop up to that number clearing intervals that are still present.
<script>
function clrTimers(){
var clr = setTimeout(function(){},10);
for( var i = 0; i < clr; i++ ){
clearInterval(i);
}
}
</script>
If you wish to skip some, then you could include them with the continue keyword if you knew them. Such as
for( var i = 0; i < clr; i++ ){
if( i == t ) continue; //I believe t was your ajax interval variable
clearInterval(i);
}
setInterval(function () { startTimer('#startDateTime', '#someID') }, 500);
Will continue to execute with the same values until it is cleared with clearInterval(). In order to clear it you need to save it a var and feed that to the clearInterval() function.

Javascript setInterval within setInterval timer increasing

I have an ajax request that refreshes a page using setInterval every 5 seconds.
Within that ajax request I have another setInterval function to blink a every half second if a condition is true.
What happens is it seems to work fine after the initial ajax call. However, with every 5 second refresh ajax refresh, my blink function timer is halved, effectively doubling the speed.
Any help would be appreciated, thanks!
Here is the code:
$(document).ready(function() {
var refreshRate = 5000;
var autoRefresh = setInterval(
function () // Call out to get the time
{
$.ajax({
type: 'GET',
success: function(data){
document.getElementById('data').innerHTML=data;
var blink = setInterval (function () {
var blink_cell = $("#blink_div").html();
if (blink_cell > 0) {
$("#blink_div").toggleClass("blink");
} else {
$("#blink_div").addClass("invisible");
}
},500);
} // end success
}); // end ajax call
}, refreshRate);// end check
}); // end ready
Be concerned with the scope of your variables and clear the blink intervall before initiating a new one.
$(document).ready(function() {
var refreshRate = 5000;
var blink = -1;
var autoRefresh = setInterval(
function () // Call out to get the time
{
$.ajax({
type: 'GET',
success: function(data){
document.getElementById('data').innerHTML=data;
if(blink>-1) clearInterval(blink);
blink = setInterval (function () {
var blink_cell = $("#blink_div").html();
if (blink_cell > 0) {
$("#blink_div").toggleClass("blink");
} else {
$("#blink_div").addClass("invisible");
}
},500);
} // end success
}); // end ajax call
}, refreshRate);// end check
}); // end ready
$(document).ready(function () {
var _url = ''; // Put your URL here.
var _checkServerTime = 5000;
var _blinkTime = 500;
function _blink() {
// Do something here.
var condition = true; // Put condition here.
if (condition) setTimeout(_blink, _blinkTime);
}
function _handleData(data) {
$('#data').html(data);
_blink();
}
function _checkServer() {
$.get(_url, _handleData);
}
setInterval(_checkServer, _checkServerTime);
});

Categories