I have a list of users where clicking on each user I get a different timestamp from which I am showing a timer which is placed in a span with id #timer
<span id="timer"></span>
And this works as it is supposed to work.
Here is a jsfiddle.
jsfiddle
It seems that the clearInterval(x); doesn't stop the previous timer though, but start a new timer, and I get this (two timers at the same time)
I have tried also to use window.clearInterval(x); but it didnt work either. Also tried setting var x inside the $(document).on('click', '.list', function() as well as outside, but nothing works.
You have a shadowed x here:
var x;
$(document).on('click','#timer',function() {
var timestamp = localStorage.getItem("LivechatExpirationTime");
var countdown = new Date(timestamp).getTime();
//alert (countdown)
var x = setInterval(function () // <-- you redeclare x, so it's different from the first one
if you just remove the second var, it will work as expected:
var x;
$(document).on('click','#timer',function() {
var timestamp = localStorage.getItem("LivechatExpirationTime");
var countdown = new Date(timestamp).getTime();
//alert (countdown)
x = setInterval(function ()
https://jsfiddle.net/wosehfc3/
Related
I want to get the last picture from ipCamera, my function is like this.
basically, after one image load. then immediately startover loop(). I prefer not to use AJAX.
var toggle= function(_imageUrl ) { //refresh include and adjust
var img = document.getElementById('image');
var updater = function(){
var time = Date.now();
var loop = function() {
ImageURL = _imageUrl + '&' + time;
console.log(time)
img.setAttribute("src", imageURL);
ImageURL = ''; //set the image.src to empty
img.addEventListener('load', function() {
setTimeout(updater ,100)
}, false);
};
loop();
}
updater();
};
This function works fine, but apparently, the Date.now() continue to stack by each loading time. Here is the result of console.log(time);
First Loop:
1417935798237
Second loop:
1417935798237
1417935798925
ThirdLoop (as it took longer to load), thus the time stack more
1417935798925
1417935800057
1417935800057
1417935801226
1417935801227
1417935801228
1417935801228
The function has to evaluate more item by each loop, before rendering the last image, in the end it still deliver the last image, but by the 20th loop. the list is immense
Question:
1. what happened?
2. How to set Date.now() to only one last timestamp?
Everytime you call loop another eventListener is added because of the img.addEventListener call. Your eventListener will be called when the image's url changes ( causing the browser to reload the image ). That eventListener should only be added once. Move that outside of the loop function.
var toggle= function(_imageUrl ) { //refresh include and adjust
var img = document.getElementById('image');
img.addEventListener('load', function() {
setTimeout(loop ,100)
}, false);
var loop = function() {
var time = Date.now();
imageURL = _imageUrl + '&' + time;
console.log(time)
img.setAttribute("src", imageURL);
imageURL = ''; //set the image.src to empty
};
loop();
};
Because you are reusing the same img object in each loop, you keep adding more and more event listeners to it each time through the loop and thus when it loads, it doesn't just call your loop once, but N times.
Probably what you want to do is to move the adding of the event listener to outside the loop so it is only added once.
You will have to test this code carefully in whatever older browsers you want to support because a few years ago, I found some reliability issues with triggering load events more than one time on the same img object.
Also, you have references in your code to both _imageURL and imageURL. Are those supposed to be different?
In my code below, different words are shown in a <div> on a keypress event or after 1500ms if no key is pressed. The elapsed time between the appearance of the word and the keypress is my reaction time and it's saved in the variable reac.
This all works fine. But now I'd like to have two adjustments:
The reaction time should be equal to 1500 if no key is pressed. As it is now, the time runs through until a key is pressed.
I want an Interval of 500ms between the disappearance of an old word and the appearance of the new one.
I assume it's setTimeout or setInterval, yet I tried and it never worked out perfectly.
Here's my script (I shortened it to make it more readable, so it is possible that I forgot to close a bracket in the example below - hope not though):
$(document).ready(function(){
var upda = function() {
(show random word in div)
};
t1 = (new Date()).getTime();
timer = setInterval(upda, 1500);
$(document).keypress(function(e){
clearInterval(timer);
var t2 = (new Date()).getTime();
reac = t2 - t1;
t1 = t2;
if (e.keyCode == 97) {
(show another random word in div)
};
timer = setInterval(upda, 1500);
});
});
You don't really want an interval, you want a timeout
The general idea is that you set an expiration of 1500ms; if the user hasn't provided the appropriate input by the expiration of that input, your timeout expires and the timeout function fires, setting the default reac value and restarting your timer.
The keypress handler would then short-circuit the expiration and record the "actual" reac.
As a side note, you probably realize that browser-based JavaScript is a bad choice for any kind of sensitive timing operations, so we'll just go ahead and assume this is for a use case where truly accurate timing data isn't of critical importance. :)
EDIT
As an exercise, I reworked the code to use timers instead of intervals, and to separate tasks into individual functions. This is only one example; other developers may take different approaches. For example, in a larger project, this would almost certainly be encapsulated in an object library that you could reuse around the application.
var expectedInput, inputTimer, reac, startTime;
var $document = $(document);
var defaultReacTime = 1500;
var delayBetweenInputs = 500;
var timerInterval = 1500;
var showWordAndWaitForInput = function () {
startTime = (new Date()).getTime();
$document.on('keypress', keypressHandler);
expectedInput = 97;
console.log('Waiting for <expectedInput> at <startTime> ::', expectedInput, startTime);
inputTimer = setTimeout(timerExpires, timerInterval);
};
var stopWaitingForInput = function () {
clearTimeout(inputTimer);
$document.off('keypress', keypressHandler);
};
var recordReacAndResetTimer = function (reactionTime) {
reac = reactionTime;
console.log('reac ::', reac);
setTimeout(showWordAndWaitForInput, delayBetweenInputs);
};
var timerExpires = function () {
stopWaitingForInput();
console.log('timer expired');
recordReacAndResetTimer(defaultReacTime);
};
var isInputValid = function (e) {
return e.keyCode === expectedInput;
};
var keypressHandler = function (e) {
console.log('input received ::', e.keyCode);
if (isInputValid(e)) {
console.log('input is valid, ask for new input');
stopWaitingForInput();
var endTime = (new Date()).getTime();
recordReacAndResetTimer(endTime - startTime);
} else {
console.log('input is invalid, keep waiting');
}
};
setTimeout(showWordAndWaitForInput, delayBetweenInputs);
Hope this helps.
I have a simple script:
var bannerNum = 2;
window.setInterval(function () {
bannerSwap(bannerNum);
}, 5000);
function bannerSwap(bannerNum) {
if (bannerNum == 5) {
bannerNum = 1;
document.getElementById('b1').style.display = "block";
document.getElementById('b4').style.display = "none";
return;
}
document.getElementById('b' + (bannerNum - 1)).style.display = "none";
document.getElementById('b' + bannerNum).style.display = "block";
bannerNum++;
return;
}
It just loops through the function every 5 seconds and swaps the banner image (4 divs, all display:none except the first, named b1 through b4). Pulling the page up, it switches the first time (bannerNum = 3), but it never switches after that. I alerted bannerNum at the end and saw that it switched from 2 to 3 and then it popped up every 5 seconds saying it was 3 over and over. So why isn't it incrementing?
Try
window.setInterval(function () {
bannerSwap(bannerNum++);
}, 5000);
Remove the bannerNum++ inside the bannerSwap function
EDIT
Your code doesn't work because you are not modifying the actual bannerNum variable, but rather a parameter you recieve with the same name.
For your code to work entirely, you should do one of the following,
Make all the modifications to bannerNum inside the setInterval function
Remove the parameter from the bannerSwap signature, so you gain scope of the global variable
As said in the comments, remove bannerNum from bannerSwap's parameter list like this:
<script>
var bannerNum = 2;
window.setInterval(function() {
bannerSwap();
},5000);
function bannerSwap() {
// Your code here (it will work)
}
</script>
I'm working on a basic alerting system in javascript that makes a basic circle clock count down and then disappear on a map I'm making.
I have however run into a small snag since I can't figure out why line 11 and 12 in the code block below (marked by arrows) don't want to do their thing.
function createTimer(sysID){
this.IDstore = sysID;
this.time = 59;
var self = this;
document.getElementById('star'+self.IDstore).style.fill="#FF0000";
this.timer = setInterval(function(){
document.getElementById('Timer'+self.IDstore).setAttribute('d', updateState(self.time));
self.time-=1;
if(self.time<=0){
-> document.getElementById('Timer'+self.IDstore).style.visibility="hidden";
-> document.getElementById('star'+self.IDstore).style.fill="#FFFFFF";
clearInterval(self.timer);
}
},1000);
this.stopTime=stopTime;
}
If I however remove the clearInterval or move them out of the if statement they work fine. But simply making them run by themself before the execution of the clearInterval like in the next code block does not work.
function createTimer(sysID){
this.IDstore = sysID;
this.time = 59;
var self = this;
document.getElementById('star'+self.IDstore).style.fill="#FF0000";
this.timer = setInterval(function(){
if(self.time>=0){
document.getElementById('Timer'+self.IDstore).setAttribute('d', updateState(self.time));
}else if(self.time>-2){
document.getElementById('Timer'+self.IDstore).style.visibility="hidden";
document.getElementById('star'+self.IDstore).style.fill="#FFFFFF";
}else{
clearInterval(self.timer);
}
self.time-=1;
},1000);
this.stopTime=stopTime;
}
Would be great to know why and if there is a simple solution.
I am generating multiple charts each with their own setInterval to refresh the data. I have it set to clearInterval when the dynamically generated container is removed - but if I reload and it has the same id the old setInterval continues to run. Is there a way to set a dynamically named setInterval that can be stopped when the replacement is generated?
Right now I'm using:
function generateChart(data, location){
var chart = new Highcharts.Chart({
// blah blah blah
}, function(chart){
setInterval(function(){
if($('#'+location).length){
// I'm doing stuff every minute
}else{
clearInterval();
}
},60000);
});
}
What happens is, the location is a randomly generated string that becomes the element ID for the container for the Highchart and if they user saves the chart it becomes the unique identifier. If the user updates the chart that's saved and reloads the chart, the old one gets .removed() and the new one generated in its place. Now the new one has the same element ID as the old one and since the old interval finds the container it wants it attempts to continue updating - which is can't since its chart went poof.
is there a way to set a dynamic variable I can use for setInterval so that I can clearInterval on it?
var blob+location = setInterval(function(){ ...
and then
clearInterval(blob+location);
You can just use an object:
var myObj = {};
var location = "somevalue";
myObj[location] = setInterval(...
clearInterval(myObj[location]);
ok - since I couldn't seem to wrap my head around some of your answers I decided to go low tech.
function genToken(){
var num = Math.floor(Math.random() * 10000);
var token = 't-' + num;
return token;
}
function genLocation(){
var chartToken = genToken();
var newChart = '<div id="'+location+'" data-token="'+chartToken+'"></div>';
$('#chartHome').append(newChart);
}
// inside my chart function
var token = $('#'+location).data('token');
setInterval(function(){
if( $('[data-token="'+token+'"]').length ){
// still there - keep going
}else{
// all gone - time to stop
clearInterval();
}
},60000);
now when I do:
$('#'+location).remove();
the token also vanishes and won't be the same if I generate a new chart with the same location id.
Stop using setInterval, use setTimeout instead (How do I execute a piece of code no more than every X minutes?):
function generateChart(data, location) {
var element = $('#'+location);
var chart = new Highcharts.Chart({
// blah blah blah
}, foo);
var foo = function() {
if(element){
// I'm doing stuff every minute
setTimeout(foo, 6000);
}
};
}
To stop it, just avoid the setTimeout or make element = null.
Maybe my code is a little bit wrong (I'm getting sleep right now), but the thing is to use setTimeout and closures.
If inside foo, something longs more than 6 seconds you will be in troubles since setTimeinterval will call it again, please watch http://www.youtube.com/watch?feature=player_detailpage&v=i_qE1iAmjFg#t=462s , so, this way you ensure that this will run 6 seconds after the last completed stuff.
I'll let this example here to posterity:
http://jsfiddle.net/coma/vECyv/2/
var closure = function(id) {
var n = 0;
var go = true;
$('#' + id).one('click', function(event) {
go = false;
});
var foo = function() {
if(go) {
console.log(id, n++);
setTimeout(foo, 1000);
}
};
foo();
};
closure('a');
closure('b');
Not sure if anyone is still looking for this solution but I ran into this problem and chose the following approach.
For anyone dynamically creating private/anonymous intervals that need to be stopped based on some event. You can simply save the interval in a variable, then transfer that variable into a data property in your html element.
// Outer scope
let pos = 1
let interval = setInterval(() => {
if (pos < 700) {
pos++;
}
htmlEl.style.top = pos + "px";
});
htmlEl.setAttribute("data-interval", interval)
This will save the numeric identifier of your interval, providing that html element is somewhere in your DOM.
Then, later you can simply extract this data attribute and use it to cancel an interval.
let intervalId = document.querySelector("#someElement").dataset.interval;
clearInterval(intervalId);