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);
}
Related
On the page there is a link with id get-more-posts, by clicking on which articles are loaded. Initially, it is outside the screen. The task is to scroll the screen to this link by clicking on it. The code below does what you need. But the event is called many times. Only need one click when I get to this element scrolling.
p.s. sorry for my bad english
$(window).on("scroll", function() {
if((($(window).scrollTop()+$(window).height())+250)>=$(document).height()){
$('#get-more-posts').click();
}
});
Try use removeEventListener or use variable with flag, just event scroll detached more at once
You can set up throttling by checking if you are already running the callback. One way is with a setTimeout function, like below:
var throttled = null;
$(window).on("scroll", function() {
if(!throttled){
throttled = setTimeout(function(){
if((($(window).scrollTop()+$(window).height())+250)>=$(document).height()){
$('#get-more-posts').click();
throttled = null;
}
}.bind(window), 50);
}
}.bind(window));
Here's an ES6 version that might resolve the scoping issues I mentioned:
let throttled = null;
$(window).on("scroll", () => {
if(!throttled){
throttled = setTimeout(() => {
if((($(window).scrollTop()+$(window).height())+250)>=$(document).height()){
$('#get-more-posts').click();
throttled = null;
}
}, 50);
}
});
The last argument of setTimeout is the delay before running. I chose 50 arbitrarily but you can experiment to see what works best.
I don't know how true it is, but it works. After the event (click), delete the element id, and then add it again, so the click is performed once. Scroll the page to the desired item, click again, delete the id and add it again. It works. Can someone come in handy.
window.addEventListener('scroll', throttle(callback, 50));
function throttle(fn, wait) {
var time = Date.now();
return function() {
if ((time + wait - Date.now()) < 0) {
fn();
time = Date.now();
}
}
}
function callback() {
var target = document.getElementById('get-more-posts');
if((($(window).scrollTop()+$(window).height())+650)>=$(document).height()){
$('#get-more-posts').click();
$("#get-more-posts").removeAttr("id");
//$(".get-more-posts").attr("id='get-more-posts'");
};
}
window.removeEventListener('scroll', throttle(callback, 50));
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>
I have a page that auto scrolls - the function scroll() below worked just fine.
I needed to add an on-hover function - which should pause the scrolling, giving the user control over the scroll.
I added some code to stop scrolling on-hover.
<script>
var theInterval;
function startScroll() {
theInterval = setInterval(scroll, 50);
}
function stopScroll() {
clearInterval(theInterval);
}
$(function () {
scroll();
$('#scrollDiv').hover(function () {
stopScroll();
}, function () {
startScroll();
})
});
function scroll() {
if (document.getElementById('scrollDiv').scrollTop < (document.getElementById('scrollDiv').scrollHeight - document.getElementById('scrollDiv').offsetHeight)) {
-1
document.getElementById('scrollDiv').scrollTop = document.getElementById('scrollDiv').scrollTop + 1
}
else { document.getElementById('scrollDiv').scrollTop = 0; }
}
setInterval(scroll, 50);
</script>
I expected that the extra functions would stop the scrolling when the user hovers over the content.
What happened was that the scrolling simply stopped
You are dropping the interval pointer from your initial call to scroll. setInterval returns an ID to the timer that is running the function at the specified cadence.
Your code is kicking off the scrolling on the last line, but not capturing this timer ID to clear -- so on 1st hover you clear a null pointer in theInterval, then on blur you're starting another timer calling scroll.
You probably notice that it gets faster because 2 logic paths are now adding 1px every 50 ms.
On the last line, you need to also set theInterval to keep track of that call, like:
theInterval = setInterval(scroll, 50)
That should fix it.
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
}
}
I am going crazy here.
I want to show an element on mouse move, and hide it 10 sec after last move of the mouse.
I wrote this:
document.addEventListener("DOMContentLoaded", function(event) {
var time = 0;
document.addEventListener("mousemove", function(event) {
console.log('$');
document.getElementsByClassName("mybar")[0].style.visibility = 'visible';
time = 0;
while (time < 11) {
setTimeout(function() {
time++
}, 1000);
console.log(time, time == 10);
if (time == 10) {
document.getElementsByClassName("mybar")[0].style.visibility = 'hidden';
}
}
});
});
<div class='mybar'>
<h1> TESTING </h1>
</div>
Why does it end up in an endless loop?
Why doesn't it exit on condition? why does the if never gets the 'true' parameter?
Notice : don't run it this way... it will kill your tab.
First, you don't need to wait for DOMContentLoaded to add an event listener to document, since if you did, you couldn't add DOMContentLoaded in the first place.
The infinite loop is because setTimeout doesn't pause the script. It schedules its callback for the time you provide, and irrespective of that time, the callbacks will not run until the current running code in the thread completes, which never happens because you don't increment the time variable.
So the loop never ends, and so the thread is never made available, so your callbacks never can run, so time can never be incremented.
Lastly, starting a setTimeout inside an event handler that shares a local variable and executes very rapidly on an event like mousemove is prone to give unexpected results. For example, in your code, every time the handler runs, it'll reset time to 0, which doesn't seem to be what you'd want.
A solution would be to ditch the loop, schedule the visibility for 10 seconds, and prevent the main part of the code in the handler from running in the meantime by using a boolean variable.
var timer = null;
document.addEventListener("mousemove", function(event) {
var myBar = document.querySelector(".mybar");
if (!myBar) {
return; // there's no mybar element
}
if (timer == null) {
myBar.style.visibility = 'visible';
} else {
clearTimeout(timer); // clear the currently running timer
}
// set to hidden in 10 seconds
timer = setTimeout(function() {
myBar.style.visibility = 'hidden';
timer = null; // clear the timer
}, 10000);
});
I also switched to querySelector instead of getElementsByClassName because it's shorter and cleaner. And I used a variable to make sure the element is found before setting the style.
You need a flag out of the mousemove scope that tells your listener that you've already ran.
if(running) return;
running = true;
In context:
document.addEventListener("DOMContentLoaded", function(event) {
var time = 0;
var running = false;
document.addEventListener("mousemove", function(event) {
console.log('$');
if(running) return;
running = true;
document.getElementsByClassName("mybar")[0].style.visibility = 'visible';
time = 0;
while (time < 11) {
setTimeout(function() {
time++
}, 1000);
console.log(time, time == 10);
if (time == 10) {
document.getElementsByClassName("mybar")[0].style.visibility = 'hidden';
}
}
});
});
Here's a way to do it with regular JavaScript. If your browser isnt ES6 compliant, you can replace the arrow functions with regular function expressions. The example hides the text after 2 seconds instead of 10, just so you can see it work without having to waste 8 extra seconds.
//hide by default
document.getElementById('myBar').style.display = 'none';
var timer = null;
var hideDivTimer = () => {
timer = setTimeout(() => {
document.getElementById('myBar').style.display = 'none';
}, 2000);
};
document.addEventListener('mousemove', () => {
clearTimeout(timer);
document.getElementById('myBar').style.display = 'inline';
hideDivTimer();
});
<body>
<div id='myBar'>
<h1> TESTING </h1>
</div>
</body>