Unable to get simple countdown program to run - javascript

My Son is trying to get this code to work as he applying for College course. He neeeds to give an explanation of how it works from the Youtube example. The problem he has & I have is we cant get the code to run.
Youtube example he is working from.
https://www.youtube.com/watch?v=u_6CqjQ-L8Q&authuser=0
This should be a simple countdown timer from 10 to zero - any ideas what I am doing wrong. Using Notepad++ to create the example & run.
<script type="text/javascript">
function countdown(secs,elem) {
var element = document.getElementById(elem);
element.innerHTML = "Please wait for "+secs+" seconds";
if(secs<1){
clearTimeout(timer);
element.innerHTML = '<h2>Countdown Complete!</h2>';
element.innerHTML += 'Click here now';
}
secs = secs--;
var timer = setTimeout('countDown('+secs+',"'+elem+'")',1000);
}
</script>
<div id="status"></div>
<script type="text/javascript">countdown(10,"status");</script>

Some issues:
secs = secs-- will not modify secs. Just secs-- would be ok.
The spelling of the function is not consistent
Some more issues, which are also present in the link you provided:
When the timer is supposed to stop, the code still continues to call setTimeout
This code uses a bad practice to pass a string to setTimeout while it is perfectly possible to pass a function.
calling clearTimeout is useless where it happens, as at that moment there is no pending one.
Working code:
function countdown(secs,elem) {
var element = document.getElementById(elem);
if(secs<1){
element.innerHTML = '<h2>Countdown Complete!</h2>'
+ 'Click here now';
return; // <---- don't call setTimeout again
}
element.textContent = "Please wait for "+secs+" seconds";
// Spelling of countdown is important. Don't use string, but bind:
setTimeout(countdown.bind(null, secs-1, elem), 1000);
}
countdown(10, 'status');
<div id="status"></div>

Related

Javascript not executing immediately, delayed until a second after page load

After a quick cobbling together of a clock app to test the JavaScript linking ability of my Flask App hosted on Heroku, I'm stumbling on the clock text not immediately filling the .innerHTML of my element.
Javascript:
// This sets our ticker to execute the function once a second.
var myVar = setInterval(function() {
myTimer();
}, 1000);
function myTimer() {
var d = new Date();
document.getElementById("clock").innerHTML = d.toLocaleTimeString();
}
The HTML is very simple, just a small h4 element with the id of "clock". I've tried document.onload as well, but whatever I try, the website loads with an empty element then fills it about one second later.
While I have your attention, why is the standard procedure for setting an interval declaring it as a variable? Is it for later reference in the program? Would it work as a naked setInterval(xxxxx);?
Thank you in advance!
setInterval runs the funtion after a specified delay, if you would like to display time on window load for example, you could call your function once in window.onload. Declaring as a variable is needed if you would like to clear the interval, I added a button as an example.
window.onload = () => {
myTimer();
}
const btnStop = document.getElementById("btn-stop");
btnStop.addEventListener('click', () => {
console.log('stopped');
clearInterval(myInterval);
})
var myInterval = setInterval(function() {
myTimer();
}, 1000);
function myTimer() {
var d = new Date();
document.getElementById("clock").innerHTML = d.toLocaleTimeString();
}
<p id="clock"></p>
<button id="btn-stop">stop</button>

Having difficulty finishing this time-based code snippet

var myVar = setInterval(myTimer, 1000);
var button = document.querySelector(".button");
function myVarFunction() {
setInterval(myTimer, 1000);
}
function myTimer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
function clockButton(document.querySelector(".button").toggle(".clockOn")){
if(button.hasAttribute("class","clockOn")){
clearInterval(myVar);
}else{
myVarFunction();
}
}
<!DOCTYPE html>
<html>
<body>
<p>A script on this page starts this clock:</p>
<p id="demo"></p>
<button onclick="clockButton()" class = "button clockOn" >button</button>
</body>
</html>
I'm trying to execute a code snippet that will display the time in real-time (using the setInterval() method) and a button that when clicked will stop the time running in real-time, but if clicked again the time will run in real-time as it did before(using .toggle() to achieve this).
here is a link to the w3schools exercise where I got this idea from:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_win_setinterval_clearinterval
For some reason the time completely dissapears, none of my code works and I can't work out why
Skip to the end if you just want the answer
First thing's first, remove your onClick event from the HTML and place it in your script. This is the recommended way to set up events.
<button class="button clockOn">button</button>
and
var myVar = setInterval(myTimer, 1000);
var button = document.querySelector(".button");
// Add the event listener here
button.addEventListener("click", clockButton);
Now there's a couple of issues, but your most prominent one is the clockButton function. What you've got here is invalid JavaScript, you cannot execute code within the parameter list of a function:
function clockButton(document.querySelector(".button").toggle(".clockOn")){
...
}
You need to move this code to the body of the function instead.
function clockButton () {
document.querySelector(".button").toggle(".clockOn");
...
}
That fixes the first problem, which is just invalid code. But the next problem you're going to face is that toggle(...) is not a function of the button element, (You may be confusing a bit of jQuery here, which has happened to me a number of times). You don't actually need this line of code though anyway, so you can remove it, and write your own class toggle.
It's fairly straightforward to write a class toggle, and you're actually doing a check already for the buttons class in your if statement, so it's a naturally obvious place for you to write the class toggle:
if(button.hasAttribute("class","clockOn")){
...
}
But unfortunately, there's a problem with the code above. Calling the hasAttribute function on an element will just check whether that attribute exists, not if it actually has a certain value. So in your case it will always be true, as you're never removing the class attribute, only changing it to something different.
To fix this up, you can use the classList functionality, which is the standard these days to deal with element classes in the native DOM API. You want to check that the element has the class clockOn so you can change the if statement to this:
if (button.classList.contains("clockOn")) {
...
}
To remove the class, you can use the remove function on the classlist like so:
button.classList.remove("clockOn");
And you can add the class back using
button.classList.add("clockOn");
So all in all, your function becomes this
function clockButton(){
if(button.classList.has("clockOn"){
clearInterval(myVar);
button.classList.remove("clockOn");
}
else {
myVarFunction();
button.classList.add("clockOn");
}
}
Now that you're here, your button should work to stop the clock, and restart it again when you click it a second time, but it's not working properly yet, because you'll notice if you click it again, the time does not stop.
This is because myVarFunction does not reassign the new interval handle to the myVar variable. Every time you call setInterval you should get a new handle. So as an example, imagine that the first time you call setInterval it assigns the handle of 123.
var myVar = setInterval(myTimer, 1000);
// myVar === 123
Now clearInterval(myVar) will clear the running interval.
The next time you set the interval, it is within myVarFunction, lets say for example, it returns 456 the next time it's called.
function myVarFunction() {
// setInterval returns `456`
setInterval(myTimer, 1000);
// myVar is still equal to `123`
}
The next time you try to clear the interval, you are clearing 123 (since you never reassigned the myVar variable) which doesn't exist, you should be clearing 456 which was the new interval you just set up.
So it's an easy fix
function myVarFunction() {
myVar = setInterval(myTimer, 1000);
}
TL;DR
Your code should look something like this
<!DOCTYPE html>
<html>
<body>
<p>A script on this page starts this clock:</p>
<p id="demo"></p>
<!-- Remove the onclick event from here -->
<button class="button clockOn" >button</button>
</body>
</html>
var myVar = setInterval(myTimer, 1000);
var button = document.querySelector(".button");
button.addEventListener('click', clockButton);
function myVarFunction() {
myVar = setInterval(myTimer, 1000);
}
function myTimer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
function clockButton(){
if(button.classList.contains("clockOn")){
clearInterval(myVar);
button.classList.remove("clockOn");
}
else {
myVarFunction();
button.classList.add("clockOn");
}
}
See it live
JSFiddle
You can check my implementation below, the time continues from the current realtimee after toggling, I guess this is what you want.
let time = document.getElementById("demo")
let myIntervalTimer;
function myStartFunction() {
if(myIntervalTimer){
clearInterval(myIntervalTimer)
}
myIntervalTimer = setInterval(myTimer, 1000)
}
function myStopFunction() {
clearInterval(myIntervalTimer)
}
function myTimer() {
let d = new Date();
let t = d.toLocaleTimeString();
time.innerHTML = t;
}
let timeClassList = time.classList
function toggleTime() {
if(timeClassList.contains('showTime')) {
myStopFunction()
}
else {
myStartFunction()
}
timeClassList.toggle("showTime")
}
myStartFunction()
<!DOCTYPE html>
<html>
<body>
<p>A script on this page starts this clock:</p>
<p id="demo" class='showTime'></p>
<button onclick="toggleTime()">Toggle time</button>
</body>
</html>

clearInterval function not clearing setInterval function

I utilized this resource to structure my code: http://www.w3schools.com/jsref/met_win_clearinterval.asp
var intervalID = setInterval(function(){ ogpeWrapper() }, 10);
function ogpeWrapper() {
$("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll('<div id="colWrapperContainer"></div>');
}(jQuery);
function myStopFunction() {
if (document.getElementById('colWrapperContainer')) {
clearInterval(intervalID);
setIntervalID = undefined;
}
}
My ogpeWrapper function is running, but the clearInterval function is not.
Basically, once $("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll(''); runs, I want the interval to stop running it.
Edit - 12:24pm CST:
This is the base code I utilize to wrap the listed elements -
(function($) {
$("#breadcrumbAds, #breadcrumbWrapper, #containerTopParsys, #leftColWrapper, #rightColWrapper").wrapAll('<div id="colWrapperContainer"></div>');
})(jQuery);
This code works, but it doesn't process the change until after the DOM has completely loaded. I need the function to work as soon as those elementals are all available. So I need to use a setInterval to process the function, then clear the interval once the function is processed.
If anyone knows of another way to do this, besides a setIterval, please let me know.
You need to create a definite if else condition within the variable so you know exactly when it will start and when it will stop. Also, because the minimum millisecond interval timing is not consistent across browsers, although you want it to detect really fast, I would recommend a "safer" number and use 100 as the minimum instead. The .length method is a handy little way for you to check if an element is on a page; You can use it as a pseudo dynamic true/false conditional. Lastly, in your .wrapAll() tag, I swapped your single and double quotes, as it is best practice to do such.
var colWrapper = setInterval(function(){
if ($('div#colWrapperContainer').length > 0) {
var doNothing = "";
clearInterval(colWrapper);
} else {
$("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll("<div id='colWrapperContainer'></div>");
}
}, 100);
Here is a working example for your reference Wrap Example
Update:
Example for putting the script inside the <body> tag (no window.load/document.ready) so that it runs independently as soon as it is loaded.
<script type="text/javascript">//<![CDATA[
//http://stackoverflow.com/questions/33483000/clearinterval-function-not-clearing-setinterval-function/33483267#33483267
//Auto Wrap Solution
//Alexander Dixon [11-02-2015]
var wrapThese = $("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper");
var colWrapper = setInterval(function () {
if ($('div#colWrapperContainer').length > 0) {
var doNothing = "";
clearInterval(colWrapper);
} else {
wrapThese.wrapAll('<div id="colWrapperContainer"></div>').addClass('success');
}
}, 100);
//]]>
</script>

Updating textarea

I've seen this problem asked before, but all the suggestions I've tried as well as some experimentation on my own have failed.
If I run the following code using Javascript, the textarea will display only the last value of i (5). If I use the alert that is commented out, then it works.
I've tried using timeout, invterval, date and time delays and even loops to delay processing but none works unless I use an alert as used in the code below when not commented out. I know some delays still allow processing to continue. I've also tried passing variables to other functions to display in the textarea from there since it appears the textarea displays the last value after exiting the function.
Any suggestions how I can get the textarea to update with each iteration so the numbers 1 through 5 are displayed one at a time?
And I'm curious why the alert will work when other methods of pausing the action won't.
Thanks.
function Go(){
var i = 0;
for(i=0; i<6; i++){
alert("This allows textarea to update with each iteration");
document.getElementById("ta").value = "";
document.getElementById("ta").value = i;
}
}
<textarea id="ta" name="display" rows="15" cols="50"></textarea>
<br /><INPUT TYPE="button" VALUE="START" onClick="Go()">
Here's another possible example using recursion:
function Go(counter){
if (counter > 5){
return;
} else {
document.getElementById("ta").value = counter;
window.setTimeout(function(){ Go(++counter) }, 500);
}
};
Go(1);
If you just passed your function as the callback to a timer, the timer would have waited the specified duration, then executed the function - which runs through all the iterations without any delays between. You have to wait between function calls (or iterations) to see the number increase. Hope that helps :)
Here is an example using scope and setTimeout
function Go(){
var i = 0,
fn = function () {
if (i >= 6) return;
document.getElementById("ta").value = i;
++i;
window.setTimeout(fn, 500);
};
fn();
}
If you want to display the numbers one at a time, use a simple interval function, then clear it when you're done:
var interval = setInterval(function() {
var textArea = document.getElementById("ta");
var currentVal = textArea.value || -1;
currentVal == 5 ? clearInterval(interval) : textArea.value = ++currentVal;
}, 2000);
And your onClick: onClick="interval">
Demo: http://jsfiddle.net/at4aX/
Some of those other methods actually spawn background threads so that forward processes can continue unabated. You need something that will pause the run until the specified time is up, or alternatively run as an event-driven mechanism.
window.setTimeout() works great for this. I used jquery to locate the objects, and wait for domready in my example. You're under no obligation to do this, I just find it easier. Fiddle here.
$(function() {
var iterations = 6;
var burndown = function() {
var value = $("#fooinput").val() - 1;
$("#fooinput").val(value);
if( value > 0) {
window.setTimeout(burndown,1000);
} else {
$("#clickme").removeAttr("disabled");
}
}
$("#clickme").click(function() {
$("#clickme").attr("disabled","true");
$("#fooinput").val(iterations);
window.setTimeout(burndown,1000);
});
});
Thanks for all your answers. I should have checked in earlier. Spent all day on this.
I'm new at Javascript and did come up with something that works on my own but it ain't
pretty. I want to learn to use Javascript correctly so I'll look over your
responses and compare. Seems I should be able to consolidate the functions I came up
with below or just learn from your suggestions posted here. I guess I should become
familiar with jquery, Ajax, etc. as I saw that used a lot in my searching for an
answer.
<body>
<textarea id="ta" name="testinput" rows="15" cols="50"></textarea>
</body>
<script language="javascript" type="text/javascript">
var i = 0;
document.getElementById('ta').innerHTML = i;
setTimeout(Test1, 3000);
function Test1(){
i++;
document.getElementById('ta').innerHTML = i;
if(i<4){ //TEXTAREA WILL STOP AT 5
setTimeout(Test2, 3000);
}
}
function Test2(){
i++;
document.getElementById('ta').innerHTML = i;
setTimeout(Test1, 3000);
}
</script>

How to kill a javascript redirect if button is pressed?

I have come up with the following code, which allows users to view a page with a movie embed for 30 seconds before redirecting them away from the page. Additionally, they can click a link to hide the div with this countdown. What I need help with is canceling the redirect (stopping it from happening) if that link is clicked, so users can continue to watch the full movie. Thanks in advance for your help!
Javascript:
<script type="text/javascript">
var settimmer = 0;
$(function(){
window.setInterval(function() {
var timeCounter = $("b[id=show-time]").html();
var updateTime = eval(timeCounter)- eval(1);
$("b[id=show-time]").html(updateTime);
if(updateTime == 0){
window.location = ("redirect.php");
}
}, 1000);
});
</script>
<script type="text/javascript">
$(document).ready(function(){
$(".slidingDiv").show();
$(".show_hide").show();
$('.show_hide').click(function(){
$(".slidingDiv").slideToggle();
});
});
</script>
HTML:
<div id="my-timer" class="slidingDiv">
You have <b id="show-time">30</b> seconds to decide on this movie.
Yes, I want to watch this one!
</div>
setInterval returns a value you can use to cancel the interval timer via clearInterval. So:
$(function(){
// +--- Remember the value from `setInterval
// |
// v
var timerHandle = window.setInterval(function() {
var timeCounter = $("b[id=show-time]").html();
var updateTime = eval(timeCounter)- eval(1);
$("b[id=show-time]").html(updateTime);
if(updateTime == 0){
window.location = ("redirect.php");
}
}, 1000);
// + Hook up a handler for the link that uses the handle to clear it
// |
// v
$("selector_for_the_link").click(function() {
clearInterval(timerHandle);
timerHandle = 0;
});
});
Note that I've put the variable inside your ready function, so it isn't a global.
Off-topic: You don't need or want to use eval in the above (in fact, you virtually never want to use eval at all, for anything). If you want to parse a string to make a number, use parseInt (and there's never any reason to eval a literal like 1). So this line:
var updateTime = eval(timeCounter)- eval(1);
becomes
var updateTime = parseInt(timeCounter, 10) - 1;
(The 10 means the string is in decimal — e.g., base 10.)
You need to use the clearInterval method.
Maybe you can use setTimeout() to do so rather than setInterval().Here is a sample.

Categories