I hope you are doing well.
I'm working on a minigame based on JS and want to prevent the user from shooting infinite bullets, so I created this condition. Which only works for the first time and then breaks for the next clicks
also to mention this whole section is inside the loop so shooting works well with or without setInterval
let shootController = true
canvas.addEventListener("click", () => {
if (shootController) {
//shooting code goes here
shootController = false;
}
});
if (shootController === false) {
setInterval(() => {
shootController = true;
}, 1000);
}
Thanks for your replies beforehand
Somehow, I defined the 'setInterval' before and outside the loop and then called that function below and outside. This one WORKS
But from curiosity, I didn't define it at the top as a function and only used it below the loop. This one didn't work.
The problem is solved, but I don't know why.
Related
Working on a memory game. Trying to use setTimeout so that the cards revert to their original state when there is not a match. The function works on the initial clicks, the cards revert no problem when they do not match each other. However once there IS a match and I continue to play through the cards no longer work with the time out, and will only revert to their original state upon the click of a third card (which is now it functions without the added setTimeout). This is very abbreviated obviously but I think I have included the related bits, if not of course let me know.
cardFlip = 0;
$box.on("click", function() {
cardFlip++;
});
else if (cardFlip == 2){
$box.css("pointerEvents", "none");
setTimeout( () => {
$(".active").removeClass("active");
$(".first").removeClass("first");
$(".second").removeClass("second");
$box.css("pointerEvents", "all");
}, 800);
cardFlip = 0;
}
I thought by having the cardFlip = 0; at the end of the function that would start the count to 0 again but I'm obviously mistaken.
Create a flag variable which will be checked for before anything is done within the time out. If the flag variable is set, the timeout should stop execution at that point. You should set this variable once you have a match.
setTimeout( () => {
if (!match) {
$(".active").removeClass("active");
$(".first").removeClass("first");
$(".second").removeClass("second");
$box.css("pointerEvents", "all");
}}, 800);
The main reason for which I suspect you're having an issue from what I can see, is because the Timeout is set to 800ms, you could be potentially clicking cards within that timeframe.
I design a new survey and in one of my multiple choice questions, the alternatives are supposed to be hidden for 1 sec and so that the user is inclined to spend more attention to the question before answering.
So far my code is only able to hide the choices but waiting and showing is still missing. (code below)
Thanks for any help or suggestions on how to solve this issue.
Qualtrics.SurveyEngine.addOnload(function () {
this.hideNextButton();
this.hideChoices();
//HERE I WOULD LIKE THE CODE TO WAIT FOR 1 sec
//HERE I WOULD LIKE THE CHOICES TO REAPPEAR ON THE SCREEN
this.questionclick = function (event, element) {
if (this.getChoiceValue(4) == true) {
this.clickNextButton();
} else if (this.getChoiceValue(5) == true) {
this.clickNextButton();
}
}
});
There are two parts of the problem here.
How to wait one second? That's done with setTimeout() and a callback function.
How to make sure the callback function works on the right object? - That's done by storing the object we want to work on in a variable.
So, without knowing anything about Qualtrics SurveyEngine, it is clear from your code that this inside the onLoad callback refers to your survey object. We will need that object later in the setTimeout callback, so let's store it. The rest is easy:
Qualtrics.SurveyEngine.addOnload(function () {
var survey = this;
// attach click event handler
self.questionclick = function (event, element) {
// using `survey` instead of `this` would work here, too
if (this.getChoiceValue(4) || this.getChoiceValue(5)) {
this.clickNextButton();
}
};
// hide buttons
survey.hideNextButton();
survey.hideChoices();
// after 1000ms, show buttons again
setTimeout(function () {
survey.showNextButton();
survey.showChoices();
}, 1000);
});
My clearInterval function is not working from a toggle button that I have created.
$('button.shuffle').click(function() {
if(isShuffling) {
clearInterval(discoLights);
isShuffling = false;
console.log('stop shuffling')
} else {
disco = setInterval(discoLights ,3000);
isShuffling = true;
console.log('start shuffling')
}
});
I am aware that this kind of question has been asked numerous times. I did a lot of research on it within SO and I could not find solution to my problem.
Here is the JSFiddle of the code I have been working on: https://jsfiddle.net/coolwebs/zLgsdno7/7/
I have tried reordering the code on several occasions, but nothing is working. I have used setInterval and clearInterval before on page load (not set with buttons) and I have not had an issue before...
Use
clearInterval(disco);
instead of
clearInterval(discoLights);
As clearInterval takes the id which is returned by setInterval
Issue is in clearInterval().
It should be clearInterval(disco) instead of
clearInterval(dicoLights).
See clearInterval
I'm trying to get a javascript function to run only once. I've seen this question has been asked before, e.g. Function in javascript that can be called only once, but I can't get the solutions in here to work. I'm not sure if it's because I've got nested functions, or whether there's something I'm missing. Essentially, I'm trying to run a function which, when a webpage is scrolled, it:
- runs a little animation on a canvas in the header
- reduces the size of the header
- leaves it at that
But when there is any subsequent scrolling, the animation keeps re-running. Here's a summarised version of the non-working code:
$(document).on("scroll",function(){
var arrange_title = function(){
//some code
};
if($(document).scrollTop()>0){
arrange_title();
arrange_title = function(){};
setTimeout(function(){
$("header").removeClass("large").addClass("small");
},1000);
}
});
I've also tried declaring a global variable, setting it to "false" in a "window.onload" function, then set it to true in an if function that runs the animation (the if function running only if the variable is false), but that doesn't stop it either. Thoughts?
What you're looking for is something along the lines of listenToOnce where the listener fires the one time, but never again. This could be modified to a number of calls, but the logic is like so:
Register the listener.
Then once the listener fires, remove it.
See .off
$(document).on("scroll",function(){
var arrange_title = function(){
//some code
};
if($(document).scrollTop()>0){
arrange_title();
arrange_title = function(){};
setTimeout(function(){
$("header").removeClass("large").addClass("small");
// $(document).off('scroll'); // or here
},1000);
}
$(document).off('scroll'); // remove listener, you can place this in the setTimeout if you wish to make sure that the classes are added/removed
});
Don't use a time out. That is why you are getting in trouble. Declare a variable outside of your function using var, that will make it global. Your code should be inside of a check for that variable. Before executing your code the first time but inside of the check, change that variable so that the code will never run again.
Try avoid setTimeout. Almost all animation can be watched for end.
function doHeaderAnimation() {
return $('header').animate();
}
function makeHeaderSmall() {
$("header").removeClass("large").addClass("small");
}
function handleScroll(event) {
if ($(document).scrollTop() > 0) {
doHeaderAnimation().then(makeHeaderSmall);
$(document).off("scroll", handleScroll);
}
}
$(document).on("scroll", handleScroll);
I'm creating a content rotator in jQuery. 5 items total. Item 1 fades in, pauses 10 seconds, fades out, then item 2 fades in. Repeat.
Simple enough. Using setTimeout I can call a set of functions that create a loop and will repeat the process indefinitely.
I now want to add the ability to interrupt this rotator at any time by clicking on a navigation element to jump directly to one of the content items.
I originally started going down the path of pinging a variable constantly (say every half second) that would check to see if a navigation element was clicked and, if so, abandon the loop, then restart the loop based on the item that was clicked.
The challenge I ran into was how to actually ping a variable via a timer. The solution is to dive into JavaScript closures...which are a little over my head but definitely something I need to delve into more.
However, in the process of that, I came up with an alternative option that actually seems to be better performance-wise (theoretically, at least). I have a sample running here:
http://jsbin.com/uxupi/14
(It's using console.log so have fireBug running)
Sample script:
$(document).ready(function(){
var loopCount = 0;
$('p#hello').click(function(){
loopCount++;
doThatThing(loopCount);
})
function doThatOtherThing(currentLoopCount) {
console.log('doThatOtherThing-'+currentLoopCount);
if(currentLoopCount==loopCount){
setTimeout(function(){doThatThing(currentLoopCount)},5000)
}
}
function doThatThing(currentLoopCount) {
console.log('doThatThing-'+currentLoopCount);
if(currentLoopCount==loopCount){
setTimeout(function(){doThatOtherThing(currentLoopCount)},5000);
}
}
})
The logic being that every click of the trigger element will kick off the loop passing into itself a variable equal to the current value of the global variable. That variable gets passed back and forth between the functions in the loop.
Each click of the trigger also increments the global variable so that subsequent calls of the loop have a unique local variable.
Then, within the loop, before the next step of each loop is called, it checks to see if the variable it has still matches the global variable. If not, it knows that a new loop has already been activated so it just ends the existing loop.
Thoughts on this? Valid solution? Better options? Caveats? Dangers?
UPDATE:
I'm using John's suggestion below via the clearTimeout option.
However, I can't quite get it to work. The logic is as such:
var slideNumber = 0;
var timeout = null;
function startLoop(slideNumber) {
//... code is here to do stuff here to set up the slide based on slideNumber...
slideFadeIn()
}
function continueCheck() {
if (timeout != null) {
// cancel the scheduled task.
clearTimeout(timeout);
timeout = null;
return false;
} else {
return true;
}
};
function slideFadeIn() {
if (continueCheck){
// a new loop hasn't been called yet so proceed...
$mySlide.fadeIn(fade, function() {
timeout = setTimeout(slideFadeOut,display);
});
}
};
function slideFadeOut() {
if (continueCheck){
// a new loop hasn't been called yet so proceed...
slideNumber=slideNumber+1;
$mySlide.fadeOut(fade, function() {
//... code is here to check if I'm on the last slide and reset to #1...
timeout = setTimeout(function(){startLoop(slideNumber)},100);
});
}
};
startLoop(slideNumber);
The above kicks of the looping.
I then have navigation items that, when clicked, I want the above loop to stop, then restart with a new beginning slide:
$(myNav).click(function(){
clearTimeout(timeout);
timeout = null;
startLoop(thisItem);
})
If I comment out 'startLoop...' from the click event, it, indeed, stops the initial loop. However, if I leave that last line in, it doesn't actually stop the initial loop. Why? What happens is that both loops seem to run in parallel for a period.
So, when I click my navigation, clearTimeout is called, which clears it.
What you should do is save the handle returned by setTimeout and clear it with clearTimeout to interrupt the rotator.
var timeout = null;
function doThatThing() {
/* Do that thing. */
// Schedule next call.
timeout = setTimeout(doThatOtherThing, 5000);
}
function doThatOtherThing() {
/* Do that other thing. */
// Schedule next call.
timeout = setTimeout(doThatThing, 5000);
}
function interruptThings() {
if (timeout != null) {
// Never mind, cancel the scheduled task.
clearTimeout(timeout);
timeout = null;
}
}
When a navigation element is clicked simply call interruptThings(). The nice part is that it will take effect immediately and you don't need to do any polling or anything else complicated.