I have a function in my .js file that is supposed to display a countdown from 10 - 0. Once it hits 0, it should open up a second page. I don't have the part where it opens the page written yet, but that isn't my current problem. My problem is that the countdown will display the number 1, and do nothing else. I'm not really sure why.
Here's the countdown function
function startCountdown() {
for (var i = 10; i >= 0; i--) {
document.getElementById("countdown").value = i;
}
}
Here is the function that calls it
function startAdPage() {
setInterval(changeAd(), 2000);
setInterval(startCountdown(), 1000);
}
Finally, here is the HTML code that it is sending to. Everything is started by the body tag calling the onload method. I know that part works, since I have it doing something else that is working properly.
<div id="counter">
<p>The Central Valley Realtors home page will display in
<input type="text" value="" class="countdown"/>
seconds</p>
</div>
The first argument to setInterval is a function. You're not passing the function, you're calling the function and passing whatever it returns, since you have () after the function name.
Also, you're not waiting between updates to the countdown field. Javascript is single-threaded, the page doesn't update until the script returns. You need this:
function startAdPage(){
var curCounter = 10;
function startCountdown() {
document.getElementById("countdown").value = curCounter;
curCounter--;
if (curCounter == 0) {
clearInterval(countdownInterval);
}
}
setInterval(changeAd, 2000);
var countdownInterval = setInterval(startCountdown, 1000);
}
Your loop inside of startCountdown is running all the way to the end of the loop, so the value ends up 0. Also, you are supposed to pass either an Anonymous function or an unexecuted function to setInterval and clearInterval without parameters. When you add () at the end of a function name you are executing the function. Change the the <input type='text' class='countdown' /> to <input type='text' id='countdown' />, then try the following:
function countdown(begin, end, interval, outputElement){
var repeat = setInterval(function(){
if(outputElement.innerHTML){
outputElement.innerHTML = begin--;
}
else{
outputElement.value = begin--;
}
if(begin === end)clearInterval(repeat);
}, interval);
}
countdown(10, 0, 1000, document.getElementById('countdown'));
Related
Spoiler; I'm completely new to jQuery/Javascript.
I have a boolean field CheckMe and an input field textField.
If textField is empty, CheckMe should not be shown else it should (this means if goes from not-empty to empty CheckMe should be hidden right away again). I want to parse a delay, say 500 ms, i.e CheckMe is shown if text is not empty and after 500 ms of the last keypress
I have tried using the debounce function from this SO answer (see my implementation below), but the problem is, CheckMe is also first hidden after 500 ms of textField being empty
<script type="text/javascript">
function debounce(fn, duration) {
var timer;
return function(){
clearTimeout(timer);
timer = setTimeout(fn, duration);
}
}
$(document).ready(function () {
const textField= $("#textField");
const CheckMe= $("#CheckMe");
CheckMe.hide();
textField.on("input", debounce(()=> {
if (textField.val()) {
CheckMe.show();
} else {
CheckMe.hide();
}
},500));
});
</script>
but that removes checkMe after 500 ms when I clear textField.
I have tried moving the debounce into the True statement i.e
...
textField.on("input", function() {
if (textField.val()) {
debounce(function(){CheckMe.show();},500)
} else {
CheckMe.hide();
}
}
but that does not show CheckMe at any point
The reason the attempt with if () { debouce(()={}); } else { immediate(); } doesn't work is due to how event handlers store the function and how debounce stores its timer.
When you run .on("input", function() { }) that function definition is stored within the event handler, ready to run. However with debounce, that's not what is being done, instead it's:
.on("input", function())
there's no function definition - it calls the function itself, which happens to return another function to be called when the event runs.
It's why there there are so many questions on SO saying something like "my code runs immediately when I do .on("input", myfunction()) when it should be .on("input", myfunction)
So that one function (the debounce) runs once per event setup - not once per input event fire, but just once when setting up the event. So there's only one instance of var timer and it's all contained within the debounce function. The event fire then calls the code inside the return function() which already has var timer defined previously in its outer scope (the previous debounce call).
If you call debounce again with a 2nd input $("#secondInp").on("input", debounce(() => ... you get a second instance of the function with its own variable (so they don't conflict between inp1 and inp2).
So you can then see that if you put this inside the event handler (in the if), you're calling a new debounce each time (not the same one).
Your attempt did nothing because your code debounce(function(){CheckMe.show();},500) simply returns the function - so you would need to do
debounce(function(){CheckMe.show();},500)();`
but even that won't work as each time it's called (each event) you get a new instance of the debounce function and a new instance of var timer.
You can use two events. Inside each event check if the "check me" should be shown or not.
The debounced one will run after 500ms and the not-debounced one will run immediately.
function debounce(fn, duration) {
var timer;
return function() {
clearTimeout(timer);
timer = setTimeout(fn, duration);
}
}
$(document).ready(function() {
const textField = $("#textField");
const checkMe = $("#checkMe");
checkMe.hide();
textField.on("input", debounce(() => {
if (textField.val()) {
checkMe.show();
}
}, 500));
textField.on("input", () => {
if (!textField.val()) {
checkMe.hide();
}
});
});
#checkMe { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="textField" type="text">
<div id='checkMe'>^-- check this</div>
is it possible to keep it in a single if-else
Given the explanation above, it is not possible using your debounce function as it is; because of the return function() { } and the single instance of timer. The key being the single instance of timer.
Without the debounce, this can be implemented in a single function, using an outer variable for the timer, but will need the debounce code repeated each time (eg for a 2nd input) - just the clearTimeout and setTimeout code - so not much - it's the "global"/outer-scope variable that becomes an issue.
$(document).ready(function() {
var textFieldTimer = null;
const textField = $("#textField");
const checkMe = $("#checkMe");
checkMe.hide();
textField.on("input", () => {
if (textField.val()) {
clearTimeout(textFieldTimer);
textFieldTimer = setTimeout(() => checkMe.show(), 500);
}
else {
checkMe.hide();
}
});
});
#checkMe { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="textField" type="text">
<div id='checkMe'>^-- check this</div>
So how can we use both: a reusable function and inside an if inside the event handler?
By storing the single instance of timer on the element itself - using .data() in the code below, but any method to store a single instance per element will also work.
Here's an example, using a single event with an if and repeated for a second input to show how it might work.
function debounce2(fn, duration)
{
var timer = $(this).data("timer");
clearTimeout(timer);
$(this).data("timer", setTimeout(fn, duration));
}
$(document).ready(function() {
$("#checkMe, #checkMe2").hide();
$("#textField, #textField2").on("input", function() {
if ($(this).val()) {
debounce2.call(textField, () => $("#checkMe").show(), 500);
}
else {
$("#checkMe").hide();
}
});
// second input confirming `timer` is per element.
$("#textField2").on("input", function() {
if ($(this).val()) {
debounce2.call(textField, () => $("#checkMe2").show(), 500);
}
else {
$("#checkMe2").hide();
}
});
});
#checkMe, #checkMe2 { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="textField" type="text">
<div id='checkMe'>^-- check this</div>
<hr/>
<input id="textField2" type="text">
<div id='checkMe2'>^-- check this</div>
Pretty much what the title says. When the countdown starts, it goes "3", "2", and then executes the function that's supposed to launch when the timer hits zero, skipping the display of the number "1".
The actual timer output is displayed in a separate div element, you'll see in my code below.
I've seen some answers on here about faulty countdown clocks but a lot of them use jQuery whereas I'm just using vanilla JavaScript and the use of libraries is still a bit confusing to me.
var count = 3;
function startTimer() {
var timer = setInterval(function() {startTimer(count);}, 1000);
if(count === 0){
clearInterval(timer);
ranCoord(); //function to run when timer hits zero.
} else {
document.getElementById("target").innerText = count;
count--;
}
}
<div class="start">
<img src="images/start-default.png" onclick="startTimer();" alt="Click Here"/>
</div>
<div id="target"></div>
I noticed that if I include the var count=3 variable inside the startTimer(); function, the countdown doesn't work either, it just stays at number 3. Does anyone know why this is?
Also, if I include the var timer = setInterval(function() {startTimer(count);}, 1000); outside the function then it runs automatically on page load, which is not what I want. I want the countdown to start on the click of a button, and found that this worked when placed inside the function.
Thanks in advance!
If the count variable is declared inside of the startTimer function, then each iteration of the timer will have its count value overwritten and so will not count down.
setInterval repeats its function indefinitely, so only needs to be called once outside of the loop, as opposed to setTimeout which only runs once and needs to be called each iteration.
An alternative approach using setTimeout would be:
function startTimer(count) {
if (count <= 0) {
ranCoord();
} else {
document.getElementById("target").innerText = count;
setTimeout(function() { startTimer(--count); }, 1000);
}
}
This version also avoids the use of a global variable, by passing the remaining count in as a parameter.
You dont need to call startTimer in the setInterval
var count = 3;
function startTimer() {
var timer = setInterval(function() {
if (count === 0) {
clearInterval(timer);
ranCoord(); //function to run when timer hits zero.
} else {
document.getElementById("target").innerText = count;
count--;
}
}, 1000);
}
function ranCoord() {
console.log("Timer hit 0")
}
img {
height: 100px;
width: 100px;
outline: 1px solid blue;
}
<div class="start">
<img src="images/start-default.png" onclick="startTimer();" />
</div>
<div id="target"></div>
I think you not need to add more code you just need to simplify it like that
var count = 3;
function startTimer() {
const timer = setInterval(function () {
document.getElementById("target").innerText = count;
count--;
if (count <= 0) {
clearInterval(timer);
ranCoord();
}
}, 1000)
}
So, I got an infinite loop to work in this function using setInterval attached to an onClick. Problem is, I can't stop it using clearInterval in an onClick. I think this is because when I attach a clearInterval to an onClick, it kills a specific interval and not the function altogether. Is there anything I can do to kill all intervals through an onClick?
Here's my .js file and the calls I'm making are
input type="button" value="generate" onClick="generation();
input type="button" value="Infinite Loop!" onclick="setInterval('generation()',1000);"
input type="button" value="Reset" onclick="clearInterval(generation(),80;" // This one here is giving me trouble.
setInterval returns a handle, you need that handle so you can clear it
easiest, create a var for the handle in your html head, then in your onclick use the var
// in the head
var intervalHandle = null;
// in the onclick to set
intervalHandle = setInterval(....
// in the onclick to clear
clearInterval(intervalHandle);
http://www.w3schools.com/jsref/met_win_clearinterval.asp
clearInterval is applied on the return value of setInterval, like this:
var interval = null;
theSecondButton.onclick = function() {
if (interval === null) {
interval = setInterval(generation, 1000);
}
}
theThirdButton.onclick = function () {
if (interval !== null) {
clearInterval(interval);
interval = null;
}
}
Have generation(); call setTimeout to itself instead of setInterval. That was you can use a bit if logic in the function to prevent it from running setTimeout quite easily.
var genTimer
var stopGen = 0
function generation() {
clearTimeout(genTimer) ///stop additional clicks from initiating more timers
. . .
if(!stopGen) {
genTimer = setTimeout(function(){generation()},1000)
}
}
}
Live demo
This is all you need!
<script type="text/javascript">
var foo = setInterval(timer, 1000);
function timer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
$(document).on("click", "#stop_clock", function() {
clearInterval(foo);
$("#stop_clock").empty().append("Done!");
});
</script>
Currently closee to finishing a slideshow using html and JavaScript. My last problem is creating stop button which needs to use a return function (I assume) Or some sort of exit function. It is an image slideshow that runs automatically, can be paused, skip image, go back an image and so on. I'd like the stop button to kill the autoRun function and set the image back to the first default image. I've set up a function which I'm guessing is totally wrong as it is not working.
The HTML
<td class="controls">
<button onClick="autoRun()">Start</button>
<button onClick="changeImage(-1); return false;">Previous Image</button>
<button onClick="pause();">pause</button>
<button onClick="changeImage(1); return false;">Next Image</button>
<button onClick="Exit();">Exit</button>
</td>
</tr>
All buttons are working besides the last one
JavaScript
var images = ["HGal0.jpg", "HGal1.jpg", "HGal2.jpg", "HGal3.jpg", "HGal4.jpg", "HGal5.jpg", "HGal6.jpg", "HGal7.jpg", "HGal8.jpg", "HGal9.jpg", "HGal10.jpg", "HGal11.jpg", "HGal12.jpg", "HGal13.jpg", "HGal14.jpg", "HGal15.jpg"];
var interval = setInterval("changeImage(1)", 2000);
var imageNumber = 0;
var imageLength = images.length - 1;
function changeImage(x) {
imageNumber += x;
// if array has reached end, starts over
if (imageNumber > imageLength) {
imageNumber = 0;
}
if (imageNumber < 0) {
imageNumber = imageLength;
}
document.getElementById("slideshow").src = images[imageNumber];
return false;
}
function autoRun() {
interval = setInterval("changeImage(1)", 2000);
}
function pause(){
clearInterval(interval);
interval = null;
}
function Exit(){
return;
}
I'm not fully understanding the return statement in the Exit function, as most examples I've looked at run the function when an 'if' statement is met, whereas I'd like mine to execute when the Stop button is clicked. Thanks
A return statement simply exits the function in which it appears, it doesn't cause other things to stop. So this:
function Exit(){
return;
}
...has the same effect as this:
function Exit() { }
That is, the function doesn't do anything at all.
I'd like the stop button to kill the autoRun function and set the image back to the first default image.
OK, so have your Exit() function call your other functions:
function Exit() {
pause(); // this will stop the slideshow
imageNumber = 0; // reset to the first image
changeImage(0); // change to that image
}
I have the following script:
var results;
var cursor = 0;
function myFunction () {
$.getJSON('list.php', function(json) {
results = json.result;
cursor = 0;
// Now start printing
printNext();
});
}
function printNext(){
if(cursor == results.length){
// Reset the cursor back to the beginning.
cursor = 0;
}
// Print the key1 in the div.
//$('#device-content-user-text').html(results[cursor].key1);
$('#device-content-user-text').hide('fast', function(){ $('#device-content-user-text').html(results[cursor].key1); $('#device-content-user-text').show('fast'); });
// Set a delay for the current item to stay
// Delay is key2 * 1000 seconds
setTimeout(function(){
printNext();
}, results[cursor].key2 * 1000);
// Advance the cursor.
cursor++;
}
var interval = setInterval(function () {
myFunction();
}, 300000); //make sql query every 5 minutes
and it gets the JSON string from the page list.php and prints the results one by one in a #device-content-user-text div. It is done every five minutes and the timer starts counting time when the user loads the page. How can I invoke this function also on the page load (and then normally every 5 minutes)?
Thanks
Use document.ready() like
$(document).ready(function(){
var interval = setInterval(function () {
myFunction();
}, 300000); //make sql query every 5 minutes
myFunction();
});
Also, if your just calling myFunction inside the anonymous function of setInterval, just pass the function reference itself
$(document).ready(function() {
var interval = setInterval(myFunction, 300000); //make sql query every 5 minutes
myFunction();
});
Update
Depending on what you meant by page 'load', there can be a world of difference between document.ready and load(). If you want to be absolutely sure everything is loaded(including frames, images, etc..) then do
$(window).load(function() {
var interval = setInterval(myFunction, 300000);
myFunction();
});
Otherwise, if it is sufficient that the DOM is ready, just stick with document.ready()
See jQuery - What are differences between $(document).ready and $(window).load?
//Document ready
$(function(){
//call function
myFunction();
//put your interval here
});