Non-working code:
<html>
<body>
<p id="timeCountBar">-></p>
<script>
var timeCountBarText = document.getElementById("timeCountBar").innerHTML;
function subCount(){
timeCountBarText="-"+timeCountBarText;
document.getElementById('timeCountBar.innerHTML').innerHTML=timeCountBarText;
}
function countTime(){
for (int i; i < 100; i++){
setTimeout("subCount",10);
}
//something to do after counting has ended
}
countTime();
</script>
</body>
</html>
Only showed -> and nothing else happened.
What should I do?
SOLVED:
HTML:
<p id="timeCountBar">-></p>
JavaScript:
var timeCountBarText = document.getElementById("timeCountBar").innerHTML;
var sc = setInterval(function(){subCount()}, 10);
var i=0;
var subCount = function() {
timeCountBarText = "-" + timeCountBarText;
document.getElementById('timeCountBar').innerHTML = timeCountBarText;
i=i+1;
if(i==100){
clearInterval(sc);
}
}
You can see it working here:
http://jsfiddle.net/aniruddha153/Ezres/
You had 3 problems:
Logic was not entirely correct.
you should not use setTimeout. Instead you should use setInterval. And the right way to declare setInterval is
setInterval(function(){subCount()}, 10);
You need to use clearInterval
Reference: JavaScript Timing Events
You have two major problems.
The first is easily discovered by looking at the JavaScript console in your browser.
JavaScript is not JavaScript, int should be var.
The second is that setTimeout is not sleep. You need to call subCount either recursively with setTimeout or by using setInterval instead of using a for loop.
Related
If I write the html:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<h1 id="message">
</h1>
and the JS:
messages = ["Here", "are", "some", "messages."]
$(function() {
for (var i = 0; i < messages.length; i++) {
$('#message').html(messages[i]).delay(1000);
}
});
and load the page, I expect to see each string in the array show up with a delay in between. However, all I see is "messages." appear. It seems that the for loop iterates immediately through each value in the array before performing any delay.
I have seen another method for getting the desired visual result (How can I change text after time using jQuery?), but I would like to know why the earlier method does not work. What is going on when this code is executed?
This is how i would delay my message changing.
function delayLoop(delay, messages) {
var time = 100;
$(messages).each(function(k, $this) {
setTimeout(function()
{
$("#message").html($this);
}, time)
time += delay;
});
}
delayLoop(1000, ["Here", "are", "some", "messages."]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="message">
</div>
All I did was for each message delay by an additional delay time.
It works in async mode so its not ui blocking and the messages will display a second after one another.
EDIT:
Removed the .delay from the .html it is redundant.
Note that jQuery's delay is specifically for effects; methods like html do not use the effects queue and are therefore not affected by delay.
This is a problem better solved with JavaScript's native setTimeout function. There are many ways to do this; in fact, you don't even need jQuery!
let messages = ["Here", "are", "some", "messages."];
let delay = 1000;
let header = document.getElementById("message");
messages.forEach(function(message, i) {
setTimeout(function() {
header.innerText = message;
}, delay * i);
});
<h1 id="message" />
You would need something along the lines of
$(function() {
for (var i = 0; i < messages.length) {
var done=false;
$('#message').html(messages[i]).delay(1000).queue(function(){
done=true;
$(this).dequeue();
});
if(done==true){
i++;
}
}
});
Thank you for the answers and comments--very helpful.
I also found this post helpful: Node.js synchronous loop, and from it wrote this (which also works):
function changeText() {
var msg = messages.shift();
$('#message').html(msg).show(0).delay(1000).hide(0, function() {
if (messages.length > 0) {
changeText();
}
});
}
(I used .show and .hide because without them only one of the array values appeared. I'm not sure why that is, but that's a question for another time.)
I am getting an issue with a large amount of processing causing the non-responsive script error in IE8 (and no, I cannot make the users use a better browser).
I then read that it should be possible to split up the tasks and cede control back to the browser in between different parts of the validation. So I decided to make a simple example based on some code I found to figure out where the breaking points are. The real code is doing lots of jquery validationengine processing.
I tried to use jsFiddle but I can't get jsFiddle to run in IE8. Bummer. So, I'll have to share inline here.
When I first load it, it seems to work just fine. I push the button and both functions finish without a problem. However, subsequent pushes causes an unresponsive script error. I've played around with the number of loops in my simulated work function. Much more than 1.25 million loops and it dies with unresponsive script.
Shouldn't separate calls to the onClick start the non-responsive counter anew? What am I missing here?
<html>
<head>
<script>
var progress = null;
var goButton = null;
window.onload = function() {
progress = document.getElementById("progress");
goButton = document.getElementById("goButton");
}
function runLongScript(){
// clear status
progress.value = "";
goButton.disabled=true;
var tasks = [function1, function2];
multistep(tasks,null,function() {goButton.disabled=false;});
}
function function1() {
var result = 0;
var i = 1250000;
for (;i>0; i--) {
result = result + 1;
}
progress.value = progress.value + "f1 end ";
}
function function2() {
var result = 0;
var i = 1250000;
for (;i>0; i--) {
result = result + 1;
}
progress.value = progress.value + "f2 end";
}
function multistep(tasks, args, callback){
var tasksClone = tasks.slice(0); //clone the array
setTimeout(function(){
//execute the next task
var task = tasksClone.shift();
task.apply(null, args || []);
//determine if there's more
if (tasksClone.length > 0){
setTimeout(function () {
multistep(tasksClone, args, callback);
}, 100);
} else {
callback();
}
}, 100);
}
</script>
</head>
<body>
<p><input type="button" id="goButton" onClick="runLongScript();" value="Run Long Script" /></p>
<input type="text" id="progress" />
</body>
</html>
You're never calling clearTimeout() to remove the one currently running when the button has been pressed already. Add an if statement before you start another setTimeout and check to see if one is already running, clear it if it is, and then continue. Here's a link that should help you if you have any questions: https://developer.mozilla.org/en-US/docs/Web/API/window.clearTimeout
I've a jsp page which sets 'timestamp' attribute to certain HTML elements. I use the value of these 'timestamp' to display time elapsed in the format - "updated 10 seconds ago" (as tooltips)
I've created a static HTML page for the demonstration of my issue.
This is my code:
<html>
<head>
<script type = "text/javascript">
function setTime() {
var currentDate = new Date();
var elem = document.getElementsByClassName('supermaxvision_timestamp');
if(elem) {
for (var i = 0; i < elem.length; i++) {
var timestamp = elem[i].getAttribute('timestamp');
if(timestamp) {
var startTimestamp = new Date();
startTimestamp.setTime(timestamp)
var difference = currentDate.getTime() -startTimestamp.getTime();
elem[i].innerHTML = difference + " milliseconds";
}
}
}
setInterval(setTime, 1000);
}
</script>
</head>
<body>
<div class='supermaxvision_timestamp' timestamp='1353389123456' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389234567' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389345678' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389456789' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389567890' ></div>
<button onclick="setTime()">start</button>
</body>
</html>
you can just copy paste this code into a text file and open it in a browser (click 'start' button only once).
The problem is that initially the values of my div will update once every second ( as the code - setInterval(setTime, 1000)). But slowly the update interval decreases and values gets updated instantaneously. And within a minute the browser stops responding.
I'm not calling setInterval from within the loop. What is possibly wrong here?
Also, this code doesn't work in IE.
setInterval(fn, ms) says run fn every ms milliseconds, from now until I clear this interval. But on each call, you set a new interval, identical to the last.
So simply change setInterval to setTimeout which does not repeat, and only calls the function provided once. setTimeout can emulate setInterval by calling a function that sets a new timeout recursively. If you do that with intervals, you schedule more and more intervals that never stop. And each time it calls itself, the number of scheduled intervals double. It gets out of hand quickly...
Alternatively, you can move the setInterval out of the setTime function and only call it once, which will keep it being called every second. Like say:
// button calls this.
function startTime() {
setInterval(setTime);
}
function setTime() {
// all that code, but minus the setInterval at the end
}
You're calling setInterval recursively. Every time a new interval is created, that interval creates a new interval. Eventually the browser cannot handle it.
Maybe you would rather something like this?
<button onclick="setInterval(setTime, 1000)">start</button>
setInterval begins a repeating function - as it is right now setTime does it's loop and logic then calls setTimeout every second, each setTimeout call then starts another repeated call to itself every second. if you use setTimeout instead, it will be called once only, but my suggestion would be that instead you simply run setInterval outside your function declaration, like:
<html>
<head>
<script type = "text/javascript">
function GEBCN(cn){
if(document.getElementsByClassName) // Returns NodeList here
return document.getElementsByClassName(cn);
cn = cn.replace(/ *$/, '');
if(document.querySelectorAll) // Returns NodeList here
return document.querySelectorAll((' ' + cn).replace(/ +/g, '.'));
cn = cn.replace(/^ */, '');
var classes = cn.split(/ +/), clength = classes.length;
var els = document.getElementsByTagName('*'), elength = els.length;
var results = [];
var i, j, match;
for(i = 0; i < elength; i++){
match = true;
for(j = clength; j--;)
if(!RegExp(' ' + classes[j] + ' ').test(' ' + els[i].className + ' '))
match = false;
if(match)
results.push(els[i]);
}
// Returns Array here
return results;
}
function setTime() {
var currentDate = new Date();
var elem = GEBCN('supermaxvision_timestamp');
if(elem) {
for (var i = 0; i < elem.length; i++) {
var timestamp = elem[i].getAttribute('timestamp');
if(timestamp) {
var startTimestamp = new Date();
startTimestamp.setTime(timestamp)
var difference = currentDate.getTime() -startTimestamp.getTime();
elem[i].innerHTML = difference + " milliseconds";
}
}
}
}
</script>
</head>
<body>
<div class='supermaxvision_timestamp' timestamp='1353389123456' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389234567' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389345678' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389456789' ></div>
<div class='supermaxvision_timestamp' timestamp='1353389567890' ></div>
<button onclick="setInterval(setTime, 1000)">start</button>
</body>
</html>
Also, the reason this is not working in IE is that it does not properly support the getElementsByClassName method of document. I found that out here: IE 8: Object doesn't support property or method 'getElementsByClassName' and Rob W also gives a good explanation there, but for a quick answer I have modified my code above to work in IE, using querySelectorAll
Derp, thats a jQuery method Chris, why would you just assume people use jQuery. getElementsByClassName & IE8: Object doesn't support this property or method includes an answer from ascii-lime which implements it's own version of getElementsByClassName. There no benefit to me copying all the code to here, but go have a look if you don't want to use jQuery.
OK, I just said there was no point, but I've copied all the code here anyway, above is a working, tested (on ie and ff) example of what you want
I have multiple paragraphs in an html-file that should show a dynamic countdown.
So I made a Countdown function in javascript, that returns the remaining time every time it is called. Unfortunately, I don't know how to call this function every second in the html file. Can you please help me out?
This is how my html file looks like:
EDIT, I have many countdown-paragraphs in my html file!:
<p class="countdown"><script>document.write(CountdownAnzeigen('2012-07-16 12:20:00'));</script></p>
<p class="countdown"><script>document.write(CountdownAnzeigen('2012-08-10 10:10:00'));</script></p>
...
The javascript function looks like:
function CountdownAnzeigen(end_datetime){
var Now = new Date();
var Countdown = Date.parse(end_datetime);
var CountdownText = Countdown.getTime()-Now.getTime();
return CountdownText;
}
setInterval(function() {
CountdownAnzeigen('2012-07-16 12:20:00');
}, 1000);
The setInterval(foobar, x) function is used to run a function foobar every x milliseconds.
Note that foobar can either be a function to be run or a string which will be interpreted as a Javascript, but I believe its accepted that using the string methodology is bad practice.
See the MDN setInterval docs.
(See also setInterval's sister method setTimeout's documentation.)
Use data- attributes to associate a target time with each element:
<p class="countdown" data-target-time="2012-07-06 12:20:00"></p>
<p class="countdown" data-target-time="2012-08-10 10:10:00"></p>
Then use a single setInterval function to fill each countdown-classed element with the result of the countdown function for its related time data:
setTimeout(function() {
var countdowns = document.getElementsByClassName("countdown");
for(var i=0; i < countdowns.length; ++i) {
var cd = countdowns[i];
cd.innerHTML = CountdownAnzeigen(cd.getAttribute("data-target-time"));
}
}, 1000);
This creates completely valid HTML5 and still functions correctly in older browsers.
Besides all answers how to use setInterval(), nobody explained, how to get the result into the paragraph. :)
So again, call you function like this:
setInterval(function() { CountdownAnzeigen('2012-07-16 12:20:00'); }, 1000);
And update the function:
// remove return value
return CountdownText;
// and replace it with this
document.getElementById('countdown').innerHTML = CountdownText;
Finally change your HTML to this:
<p class="countdown" id="countdown"></p>
If you don't use any "onload"-handler, place all your JavaScript below the paragraph and call the function once manually, to have the start time immediately and not the first time after one second.
EDIT
If you have multiple paragraphs you could do it like this:
<p class="countdown" id="countdown_1"></p>
<p class="countdown" id="countdown_2"></p>
<script>
setInterval(function() { CountdownAnzeigen('countdown_1', '2012-07-16 12:20:00'); }, 1000)
setInterval(function() { CountdownAnzeigen('countdown_2', '2012-07-16 12:20:00'); }, 500)
</script>
And update the function to:
document.getElementById(id).innerHTML = a;
Where ìd is a new parameter from the function call.
You can call function periodically also via the setTimeout().
Example:
javascript
function CountdownAnzeigen(countdown){
document.getElementById('countdown').innerHTML = countdown--;
if (countdown>0) {
window.setTimeout(function(){CountdownAnzeigen(countdown);}, 1000);
} else { alert('The End');}
}
html
<input type="button" value="count down" onclick="CountdownAnzeigen(10)"/>
<div id="countdown"></div>
I'm very new to javascript and I'm trying to do something I thought would be very basic.
I've created a countdown timer and used "i" as my variable to hold a number from 0-5. And I have an array of "d" from d[0] to d[5] containing strings.
I'm trying to make the timer countdown pass the "i" value into an innerHTML method array value so I want it to display d[5]... d[4]...d[3]... etc.
What am I doing wrong!? Please Help!
<html><head><script language="javascript" type="text/javascript">
var d=new Array():
d[1]="One";
d[2]="Two";
d[3]="Three";
d[4]="Four";
d[5]="Five";
var i=5;
var i=setInterval("timer()",2000); //1000 will run it every 1 second
function timer() {
i--;
if (i <= 0)
clearInterval(countD);
return;
}
}
document.getElementById(timer).innerHTML = d[i];
</script>
</head>
<body>
<h1>
<p id="timer"></p>
</h1>
</body>
</html>
Also, document.getElementById(timer).innerHTML = d[i];
should be document.getElementById("timer").innerHTML = d[i];
id names need to have quotes around them because they are not names of variables. The variable 'timer' is undefined.
Also, you are missing a curly brace on the line if (i <= 0). I am assuming that you meant to exit the function if this if statement is true.
Also, you have a colon instead of a semicolon on the line var d=new Array():
Also, you can't have a paragraph tag inside of an h1
Also, you should encapsulate all of this javascript into a function called something like init. I believe that the javascript code in the head runs before the html is loaded. The javascript can't therefore find the tag. Then, use <body onload="init()"> as your body tag.
EDIT: As the commenters have stated, you are using the variable i for multiple unrelated things.
I'm sorry to say but your code is quite a mess; here's one way to get your code to work, along with a working example:
<html>
<head>
<script language="javascript" type="text/javascript">
var d=new Array();
d[0]="One";
d[1]="Two";
d[2]="Three";
d[3]="Four";
d[4]="Five";
var i=4;
var myTimer =setInterval(timer,2000); //1000 will run it every 1 second
function timer() {
document.getElementById("timer").innerHTML = d[i];
i--;
if (i < 0){
clearInterval(myTimer);
}
}
</script>
</head>
<body>
<h1>
<p id="timer"></p>
</h1>
</body>
</html>
The problems with your JavaScript
You've got two declarations for i, one after the other - one is set to 5 and the other to the setInterval timer
What is countD in clearInterval(countD);?
document.getElementById(timer).innerHTML = d[i]; is attempting to use the function timer as the argument to getElementById. It should be in quotes: document.getElementById("timer").innerHTML = d[i];
It is also being invoked only once since it's not inside the function that is being called by the timer.
var d=new Array(): should be terminated by a ;(semi-colon) and not a : (colon)
You have unmatched braces - your if statement doesn't have an opening brace ({) but it does have a closing one.
Note that while setInterval("timer()", 1000) is valid JavaScript, it depends on eval which should be avoided if possible. The alternate, preferred way to use this is setInterval(timer, 1000) i.e. passing the function and not a string.