I am not really sure how to tackle this as I don't understand what I am doing wrong - so, every time I click on created "start" button, a setInterval is triggered:
$("#questBox").on("click", "#startQuestButton", function(){
document.getElementById("startQuestButton").classList.add("hidden");
var requiredTime = 10000;
var timer = 0;
var interval = setInterval(function(){
if(timer>requiredTime){
clearInterval(interval)
document.getElementById("startQuestButton").classList.remove("hidden");
}
timer+=1000;
}, 1000);
}
And the startQuestButton is a div, present in my html file:
<div id="startQuestButton"></div>
Now, when I click on the start button the second time, 2 identical setIntervals are triggered, 3 the third time and so on.
I have even tried to set the interval to null before and after I click on the start button. Also, the start button is hidden for as long as the interval is in process. I want to completely destroy the previous interval so that only one gets triggered as I press t the start button.
I need setInterval to display a progress bar, that imitates a loading bar (so, every second, the width of a colored element is enlarged by a few pixels).
That's because setInteval() doesn't return an interval object (no such thing exists afaik) but it's id
so when you clear you clear only the last one created because it is the id saved in interval
var requiredTime = 2000;
var timer = 0;
var interval
function createInterval() {
interval = setInterval(function(){
if(timer>requiredTime){
console.log(`cleared interval : ${interval}`)
clearInterval(interval)
}
timer+=500;
}, 500);
console.log(`created interval : ${interval}`)
}
document.getElementById("b").onclick = createInterval
<button id="b">clickMe</button>
to have only one at a time the idea is to clear before recreating
var requiredTime = 2000;
var timer = 0;
var interval
function createInterval() {
// as pointed by Barmar the if here is not useful in production since clearInterval with a parameter that is not an interval id do nothing silently
// I only keep it to prevent this snippets to log "cleared interval : undefined"
if(interval) {
clearInterval(interval)
console.log(`cleared interval : ${interval}`)
}
interval = setInterval(function(){
if(timer>requiredTime){
clearInterval(interval)
console.log(`cleared interval : ${interval}`)
}
timer+=500;
}, 500);
console.log(`created interval : ${interval}`)
}
document.getElementById("b").onclick = createInterval
<button id="b">clickMe</button>
Related
i try to make a button that get the time now ,put it in element and updated every one second using the event listener the problem that the time disappear immediately
var time
function updateTime(){
time = new Date().toLocaleTimeString();
document.getElementById('showtime').innerHTML=time
setInterval(updateTime, 1000);
}
document.getElementById("btnclock").addEventListener("click", updateTime);
html
<button id="btnclock"> Start Clock</button>
<p id='showtime'> </p>
Update can call setInterval(), but, as others have pointed out, we only want at most one interval timer running. This can be expressed tersely with a nullish coalescing assignment (not so tersely named).
Below, once the intervalID has been initialized, the setInterval() will no longer be evaluated. Keeping the interval id around is useful because it allows for a stop button, also demonstrated...
let intervalID;
function updateTime(run) {
document.getElementById('showtime').innerHTML = (new Date()).toString()
intervalID ??= setInterval(updateTime, 1000);
};
document
.getElementById("btnclock")
.addEventListener("click", updateTime);
document
.getElementById("btnclock-stop")
.addEventListener("click", () => {
clearInterval(intervalID)
intervalID = null; // so the setInterval assignment can run
});
<button id="btnclock"> Start</button>
<p id='showtime'> </p>
<br/>
<button id="btnclock-stop"> Stop</button>
The issue is that when you click the button, updateTime function calls setInterval(updateTime, 1000) which creates a timer. The timer calls updateTime function every second. But updateTime creates another timer while the first one is still running. So in fact what is happening is that every second every running timer creates a new timer so after 10 seconds you will have 1024 timers running at the same time. This is obviously not what you want.
Try something like this:
var timer = 0;
function startTimer() {
if (!timer) {
timer = setInterval(updateTime, 1000);
}
}
function stopTimer() {
clearInterval(timer);
timer = 0;
}
function updateTime() {
var time = new Date().toLocaleTimeString();
document.getElementById("show-time").innerHTML = time;
}
document.getElementById("start-clock").addEventListener("click", startTimer);
document.getElementById("stop-clock").addEventListener("click", stopTimer);
<button id="start-clock">Start Clock</button>
<button id="stop-clock">Stop Clock</button>
<p id="show-time"></p>
It is important to destroy the timer when you no longer need it. Function clearInterval does it.
I am looking for a way to call a function that should wait for 1000 miliseconds before executing. And when the function is called again before the 1000 miliseconds are reached, the timer should restart. So that the function runs 1000 miliseconds after the last time it was called.
So let's say I have a button:
<button type="button" id="btnclick">Click Me!</button>
And I want to display an alert after exactly 1000 miliseconds after the last time it was clicked. But when the button is clicked a second time, before the 1000 miliseconds have past, then the timer should restart.
If someone clicks the button 1 time, then the alert displays 1 second after the click.
If someone clicks the button, and then clicks again after 999 miliseconds, and then again after again 999 miliseconds, then I want to run the function 1 second after the last click (so 2,98 seconds after the first click).
Is this possible? And how?
My Best guess would be something like:
function delay(callback, ms) {
var timer = 0;
return function () {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
callback.apply(context, args);
}, ms || 0);
};
}
$('#btnclick').click(function(e){
console.log('I want to see this everytime the button is clicked, without any delay');
delay(waitFunction(),1000);
});
function waitFunction(){
console.log('I want to see this 1 second after the LAST click');
}
(inspiration from: Wait for function till user stops typing )
Yes it is possible. you just have to check if an timeout is already counting down and, if it is, reset it. Here is a simple example.
// set timer-variable
var timer = null;
//on button-click
$('#btnclick').click (function (e) {
//clear timeout if already applied
if (timer) {
clearTimeout (timer);
timer = null;
}
//set new timeout
timer = setTimeout (function () {
//call wait-function and clear timeout
waitFunction ();
clearTimeout (timer);
timer = null;
}, 1000);
});
function waitFunction () {
console.log ('I want to see this 1 second after the LAST click');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="btnclick">Click Me!</button>
I used lastclick variable to store date user clicked.
I defined lastclickworked variable to avoid double setTimeout calls. In settimeout function, i checked if 1 second passed, run the code. if 1 second doesn't passed then call settimeout again with 1 seconds- passed time
var lastclick=null;
var lastclickworked=true;
function clickMe(){
lastclick=new Date();
if(lastclickworked)
runcallback(1000);
}
function runcallback(milliseconds){
lastclickworked=false;
setTimeout(function(){
var current = new Date();
var milliseconds = (current.getTime() - lastclick.getTime());
if(milliseconds<1000){
runcallback(1000-milliseconds);
}else{
lastclickworked=true;
console.log('you clicked 1 second ago');
}
},milliseconds);
}
<button onclick="clickMe();">Click Me!</button>
I am building a memory card game. the class .deck represents a deck of cards. Each time I click a card the timer speeds up. How do I prevent the timer from speeding up?
function startTimer() {
$(".deck").on("click", function () {
nowTime = setInterval(function () {
$timer.text(`${second}`)
second = second + 1
}, 1000);
});
}
You start multiple intervals, one each click. You probably should just start one. If you want to start it for the first card that is clicked:
function startTimer() {
// Maybe remove old timer? Should happen somewhere in your code.
// Possibly "stopTimer" if you have such a function.
clearInterval(nowTime);
let started = false;
$(".deck").on("click", function () {
if (started) return;
nowTime = setInterval(function () {
$timer.text(`${second}`)
second = second + 1
}, 1000);
started = true;
});
}
That code should have some more cleanup, though. Otherwise you accumulate a lot of dead event listeners.
(Furthermore, i believe that jQuery should never be used.)
You need to stop the previous timer before starting a new one because, if you don't, you wind up with multiple timer callback functions all executing one immediately after the other, which gives the illusion that your single timer is speeding up.
function startTimer() {
$(".deck").on("click", function () {
clearInterval(nowTime); // Stop previous timer
nowTime = setInterval(function () {
$timer.text(`${second}`);
second = second + 1;
}, 1000);
});
}
Another way to deal with this is to only allow the click event callback to run the very first time the button is clicked:
function startTimer() {
$(".deck").on("click", timer);
function timer() {
nowTime = setInterval(function () {
$timer.text(`${second}`);
second = second + 1;
}, 1000);
$(".deck").off("click", timer); // Remove the click event handler
}
}
It's a follow up to this question - https://stackoverflow.com/a/33430608/3766930
Basically I have a text area and when user starts typing in sth, the counter starts going down from 3 to 0. when it reaches 0 it gets disabled.
Now I want to add a feature of starting over - when user clicks the link start over, text area goes enabled again and user has 3 seconds (again) to perform the input.
I modified the jquery script:
$('#textArea').on('input propertychange', display30Seconds);
var interval;
function display30Seconds() {
var validTime = 3000;
if (!interval)
interval = setInterval(function () {
$('#counter').html(validTime / 1000);
validTime = validTime - 1000;
if (validTime < 0) {
clearInterval(interval);
alert('Time Up!');
$('#textArea').prop('disabled', true);
$('#counter').html('start over');
$('#counterIsDone').on('click', function(){
$('#textArea').prop('disabled', false);
display30Seconds();
});
}
}, 1000);
}
but I see that I cannot call the method display30Seconds(); again. Or rather I can, but the interval is not set again. How can I fix it?
Seems like I'm not entering the code inside
if (!interval)
because the interval is not visible any more after clearing it (?). So I thought about moving the var interval; into the body of the method function display30Seconds() {, but that doesn't bring the expected effect. Is there a way of fixing it?
Here is my updated fiddle: http://jsfiddle.net/jf4ea4nx/3/
Set interval=null after the clearInterval() call.
What seems to confuse you is the semantics of clearInterval(interval). As Patrick Evans points out in his comment, it will not set interval to a value that evaluates to false in a condition.
To make it completely clear you could use a boolean variable such as countdownRunning in addition to the interval variable to keep track of whether the countdown is active or not.
Try this:
$('#textArea').on('input propertychange', display30Seconds);
var interval=false;
function display30Seconds() {
var validTime = 3000;
if (!interval)
interval = setInterval(function () {
$('#counter').html(validTime / 1000);
validTime = validTime - 1000;
if (validTime < 0) {
clearInterval(interval);
alert('Time Up!');
$('#textArea').prop('disabled', true);
$('#counter').html('start over');
$(document).on('click','#counterIsDone', function(){
$('#textArea').prop('disabled', false);
display30Seconds();
});
interval=false;
}
}, 1000);
}
You can improve your code by using a conditional recursive call to to your iterative function instead - each call has a one second delay, which makes it slightly more intuitive to use (think of each call as one tick):
var seconds = 3;
$('#textArea').on('input propertychange', setTimeout(timeout.bind(null, seconds), 1000));
function timeout (iterations) {
$('#counter').html(iterations);
if (iterations === 0) {
alert('Time Up!');
$('#textArea').prop('disabled', true);
$('#counter').html('start over');
$('#counterIsDone').on('click', function(){
$('#textArea').prop('disabled', false);
timeout(seconds);
});
}
else {
setTimeout(timeout.bind(null, --iterations), 1000);
}
}
The bind function simply binds the arguments of the bind function to the arguments of the timeout call - the first argument to the bind function declares its this scope; but don't worry about that too much.
You can modify the duration of the timer by changing the seconds var. Hope this helps :)
I have setInterval problem. I made something similar to load bar. When I click mouse I fire expanding width of my block called loadBar1
// here preset of interval and loadbar...
var interval = 0;
createLoadBar1 = function() {
loadBar1 = {
// another stuff
width:0,
};
document.onclick = function (mouse) {
interval = setInterval(expandLoadBar1, 60);
}
It's expands by the help of this function:
function expandLoadBar1() {
if(loadBar1.width < 60) {
loadBar1.width++;
}
if (loadBar1.width >= 60) {
loadBar1.width = 0;
clearInterval(interval);
}
}
It's very simple above and works well when I click just once but I start having problems when I click more that one time by mouse clicking, it's logically cause the faster loadBar1.width expanding twice and after second or more mouse click the clearInterval for interval stops working and just continue raising expanding speed when I click more.
You probably need to clear the interval when the user clicks:
document.onclick = function () {
clearInterval(interval);
interval = setInterval(expandLoadBar1, 60);
}