Javascript : Do Action after elapsed time - javascript

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.

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.

Change background images using setTimeout

I have 31 images and I want to display them one after another as the background of a div. I only want it to change when the user hovers over the div. My problem right now is that it just flips through all the images really fast. I am attempting to use setTimeout, but it isn't working. How can I make the delay work?
The name of the div is About_Me_Block and the images are called frame1.gif,frame2.gif ...etc
Here is my code:
function changeImg(counter) {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
}
$(document).ready(function() {
var hoverAnimate = []
"use strict";
$('#About_Me_Block').mouseenter(function() {
hoverAnimate[0] = true;
var counter = 0;
while (hoverAnimate[0]) {
console.log(counter);
setTimeout(changeImg(counter), 1000);
counter++;
if (counter === 32)
hoverAnimate[0] = false;
}
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate[0] = false;
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
setTimeout doesn't wait for the function to end, it works lile threading in other languages.
To achieve a what you want, you need to call setTimeout from the changeImg function.
var counter = 0;
$(document).ready(function() {
var hoverAnimate = []
"use strict";
$('#About_Me_Block').mouseenter(function() {
hoverAnimate[0] = true;
counter = 0;
changeImg();
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate[0] = false;
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
function changeImg() {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
counter++;
if (counter < 32 && hoverAnimate[0]) {
setTimeout(changeImg, 1000);
} else {
hoverAnimate[0] = false;
}
}
the reason they happen all at once is because while statement doesn't have delay, so all setTimeout will be set up at the same time, thus, calling changeImg all at once.
To solve this problem, you can replace setTimeout with setInterval. Instead of using while, you can just call setInterval like
var counter = 0;
var myTimer = setInterval(changeImg, 1000);
and update counter inside changeImg every time it gets called. After looping, don't forget to
clearInterval(myTimer)
It seems you need to read up on how setTimeout works. It essentially places a reminder to run a function after a given amount of milliseconds have passed. So, when you do setTimeout(changImg(counter), 1000) you are calling changImg(counter) which returns undefined. Therein producing this setTimeout(undefined, 1000) which is why it flips really fast.
So, you can use bind to allow the function to be called later with that parameter built in. Also, make sure you remove the reminders once done with clearTimeout.
function changeImg(counter) {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
}
$(document).ready(function() {
var hoverAnimate = false, id;
function loop(counter) {
if(hoverAnimate || counter < 32) {
changeImg(counter);
id = setTimeout(loop.bind(this, counter++), 1000);
}
}
$('#About_Me_Block').mouseenter(function() {
hoverAnimate = true;
id = setTimeout(loop.bind(this, 0), 1000);
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate = false;
// Don't want a reminder for a random counter to wake up.
clearTimeout(id);
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
Two methods for timers - setTimeout and SetInterval (single / repeating)
// setInterval is also in milliseconds
var intervalHandle = setInterval(<yourFuncToChangeImage>,5000);
//this handle loop and make example loop stop
yourelement.yourEvent = function() {
clearInterval(intervalHandle);
};

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);
});

Repeat code every x seconds but not if [insert check here]

This is a followup to this question, where I found out how to make code be repeated every x seconds. Is it possible to make an event that can change this? I.e. I have a checkbox which is meant to control whether this is repeated or not, so I figured I'd need something like this:
$(checkbox).bind("change", function() {
switch(whether if it is ticked or not) {
case [ticked]:
// Make the code repeat, while preserving the ability to stop it repeating
case [unticked]:
// Make the code stop repeating, while preserving the ability to start again
}
});
I have no idea what I could put in the cases.
You can do it by assigning your setInterval function to a variable.
var interval = setInterval(function() { }, 1000);
and then you can stop setInterval by
clearInterval(interval);
p.s.
to start your interval you need to call var interval = setInterval(function() { }, 1000); again
You can either stop and start the interval:
var timer;
function start() {
timer = window.setInterval(function(){
// do something
}, 1000);
}
function stop() {
window.clearInterval(timer);
}
start();
$(checkbox).bind("change", function() {
if ($(this).is(':checked')) {
start();
} else {
stop();
}
});
Or you can have a flag causing the interval to skip the code:
var enabled = true;
var timer = window.setInterval(function(){
if (!enabled) {
// do something
}
}, 1000);
$(checkbox).bind("change", function() {
enabled = $(this).is(':checked');
});
function fooFunc() {
$('#foo').text(+new Date());
}
var id;
var shouldBeStopped = false;
$('input').change(function() {
if (shouldBeStopped)
clearInterval(id);
else
id = setInterval(fooFunc, 200);
shouldBeStopped = !shouldBeStopped;
});​
Live DEMO

Impose a wait between two submits

I have a form which does an AJAX action when submitting. Just after a user has submitted the form, I'd like to impose a minimal waiting time of 5sec to post one more time.
What the better way ? I made this script (doesn't work but I guess idea is here):
$("form#submit_under_wall"+array[1]).submit(function() {
var submit_timestamp=0;
var c = new Date();
var now = ISODateString(c);
if(now-submit_timestamp>5){
var d = new Date();
var timestamp_message = ISODateString(d);
submit_timestamp = timestamp_message ;
//AJAX ACTION
}else{ alert("Wait 5sec between each post."); }
return false;
});
This doesnt work because the timestamp is reset every time they submit, you need to move submit_timestamp outside of the function. Also, that 5 should probably be 5 * 1000
something like this (not tested):
var submitTime = (new Date()).getTime() - 5000; //let user submit if he clicks within 5s of page load
$("form#submit_under_wall"+array[1]).submit(function(e) {
var now = (new Date()).getTime();
if(now-submitTime > 5000){
submitTime = (new Date()).getTime();
//AJAX ACTION
} else {
alert("Wait 5sec between each post.");
}
e.preventDefault();
});
The easiest and most standard way would be to use Javascript native setTimeout method.
var last_action;
function ajax_action() {
last_action = Date.getTime();
// AJAX STUFF
}
$("form#submit_under_wall"+array[1]).submit(function(e) {
e.preventDefault(); // Sexier than 'return false'
if(last_action != undefined) {
setTimeout(ajax_action, Date.getTime()-last_action); // Wait for 5s before doing the action
} else {
ajax_action();
}
});
use window.setTimeout()
Wrap what you want to do in a function (eg function foo (){ alert('test'); })
Call it with a 5 second delay setTimeout(foo,5000)

Categories