Javascript increment not working - javascript

Well I did not know what exactly would be a good title for this because it is a most peculiar situation or I'm abnormally dumb.
Here's what im trying to do.
Create a simple <meter> tag which is new in HTML5. The main issue is with my javascript. Im trying to increment the value of the meter tag gradually in my javascript. But somehow it doesn't work the way i want.
JavaScript.
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
}
I'm trying to increase the value of the meter gradually every 250 ms.This doesn't happen. Instead the meter jumps straight to 10.
What interested me was the value of i that i got in the console. I got instances of 10, instead of 1,2,3...10.
Why does this happen?
FIDDLE

It's a JavaScript closures' classic. Here i is an actual reference to the variable, not its copy. After you've iterated through the loop it has the value of 10, that's why all log invocations write 10 to log.
This should work better:
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function (i) {
return function() {
console.log(i);
a.value = i;
};
}(i), 250 * i);
}
Here the most inner i is the setTimeout's callback argument, not the variable which you've declared in the loop body.

You should read more about closures in JavaScript. When a variable gets closed over, it's the same exact variable, not a copy. Since setTimeout is asynchronous, the whole loop finishes before any of the functions run, therefore the i variable will be 10 everywhere.
DEMO
function incMtrAsync(max, delay, el) {
if (el.value++ < max) {
setTimeout(incMtrAsync.bind(null, max, delay, el), delay);
}
}
incMtrAsync(10, 250, document.getElementById("mtr1"));
The above implementation implements the loop using a recursive approach. Everytime inMtrAsync is called, it checks if the value of the meter reached the max value, and if not, registers another timeout with a callback to itself.
If you want to delay the initial increment as well, just wrap the first call in another timeout.
setTimeout(incMtrAsync.bind(null, 10, 250, document.getElementById("mtr1")), 250);

Nobody used setInterval, so here's my solution ( http://jsfiddle.net/Qh6gb/4/) :
var a = document.getElementById("mtr1");
var i = 0;
var interval = setInterval(function () {
console.log(i);
a.value = ++i;
if (i == 10) {
clearInterval(interval);
}
}, 250);

The problem you describe happens before the asyncronous call to setTimeout in your original version sees a value of 10 for i because that is its value at the moment the callback is executed.
So, this is a problem with the scope of the closure, to make it work you should make it like this:
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
(function (i, a) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
})(i, a);
}
also, since a is always the same, this should be better:
var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 250);
})(i);
}
If then you want to see the counter "ticking up", this will make it visible:
var a = document.getElementById("mtr1");
for (var i = 0; i <= 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
a.value = i;
}, 1000 * i);
})(i);
}
See http://jsfiddle.net/LDt4d/

It happens because you called setTimeout, which is "asynchronous". So setTimeout is called 10times but after whole loop is done then it is executed. Therefore, i = 10 in each call...
http://jsfiddle.net/Qh6gb/9/
there is the solution:
var i = 1,
meter = document.getElementById("mtr1");
function increase() {
meter.value = i++;
console.log(i);
if(i<=10) {
setTimeout(increase, 250);
}
}
setTimeout(increase, 250);

you can use timeout jquery plugin:. It is easier
However you should calculate your timeout ,
For you ,timeout=250*max=250*10=2500
So
$('meter').timeout(2500);
Demo

Run for loop inside the function instead of declaring a closure in every step of the loop.
JSFIDDLE: http://jsfiddle.net/Qh6gb/3/
var a = document.getElementById("mtr1");
setTimeout(function () {
for (var i = 0; i < 10; i++) {
console.log(i);
a.value = i;
}
}, 250);

I hope I understand right. Please try and tell me if you got solution.
var count = 0;
function increment(){
document.getElementById("meter").value = count;
count++;
if(count ==10)
count=0;
}
setInterval(increment, 250);
Please check with jsFiddle

You're creating multiple functions that are all being set off at the same time.
Multiply the timer by i for correct delay.
for (var i = 0; i <= 10; i++) {
var a = document.getElementById("mtr1");
setTimeout(function () {
console.log(i);
a.value = i;
}, 250 * i);
}

Related

fail to setTimeout in a for loop

I'm building a simon game. And after each round the player should see the moves he must play in the next round. So i created a function showMoves which flashes the square he has to play. The problem is that the function is not showing anything. Can anyone tell me what did i miss?
// the effect
function flasher(index) {
$(moves[index]).fadeIn(50).fadeOut(50).fadeIn(50).fadeOut(50).fadeIn(100);
}
var interval2;
// show the moves that supposed to be played
function showMoves() {
for (var i = 0; i < moves; i++) {
if (i === 0) {
interval2 = setTimeout(flasher(i), 1000);
} else {
interval2 = setTimeout(flasher(i), (i+1) * 1000);
}
}
}
setTimeout accepts a function as a first parameter. I assume that by calling flasher you tried to avoid this situation. In you case, this should be done like this:
function showMoves() {
for (var i = 0; i < moves; i++) {
if (i === 0) {
interval2 = setTimeout(function(i) {return function() {flasher(i)}}(i), 1000);
} else {
interval2 = setTimeout(function(i) {return function() {flasher(i)}}(i), (i+1) * 1000);
}
}
}
The setTimeout and setInterval are a little diffrent than we think about them.
They are save some event on specified times that will be fired in its times. Because of this they has a problem with loops:
for(i=0;i<3;i++)
{
setTimeout(function(){alert(i)}, i*1000);
}
after ending the loop the browser has 3 jobs to do:
alert(i) after 1 second
alert(i) after 2 seconds
alert(i) after 3 seconds
But what is the value of 'i'. If you are in c# programming after ending the loop 'i' will be disposed and we have not that.
But javascript does not dispose 'i' and we have it yet. So the browser set the current value for i that is 3. because when 'i' reaches to 3 loop goes end. Therefor Your browser do this:
alert(3) after 1 second
alert(3) after 2 seconds
alert(3) after 3 seconds
That is not what we want. But if change the above code to this:
for(i=0;i<3;i++){
(function (index)
{
setTimeout(function () { alert(index); }, i * 1000);
})(i);
}
We will have:
alert(0) after 1 second
alert(1) after 2 seconds
alert(2) after 3 seconds
So as Maximus said you mast make the browser to get value of i currently in loop. in this way:
setTimeout(function(i) {return function() {flasher(i)}}(i), (i+1) * 1000);
i does not leave out until end of loop and must be get value just now.
What I can derive from your code is that moves is an array, but you're using it as if it's an integer in the for loop. And that's why nothing happens at all.
Replace:
for (var i = 0; i < moves; i++) {
With:
for (var i = 0; i < moves.length; i++) {
And you should see things happening.
But you will notice flasher is called immediately, without timeout. And that's because the result of flasher is set to be called, instead of flasher itself.
Other answers here suggest using an wrapper function, but this requires workarounds to correctly pass the index to the function called by setTimeout.
So assuming that it doesn't have to run in IE8 and below, the following is the most concise solution:
setTimeout(flasher.bind(null, i), (i+1) * 1000)
Full working example:
var moves = [1, 2, 3, 4];
function flasher(index) {
console.log('move', moves[index]);
}
var interval2;
// show the moves that supposed to be played
function showMoves() {
for (var i = 0; i < moves.length; i++) {
interval2 = setTimeout(flasher.bind(null, i), (i+1) * 1000);
}
}
showMoves()

Add delay between 'for' loop iterations

I'm trying to implement basic 60 sec counter(A p element with idcounter), that is triggered after a button(counter_start()) is pressed.But I want delay of 1 sec between this and make sure this updates in browser window in real-time
<script type="text/javascript">
function counter_start(){
x=0
for(i=0;i<60;i++){
x++;
document.getElementById("counter").innerHTML=x;
}
}
</script>
P.S: There might be other simple methods of implementing a timer.But it's not about timer...actually I'm a student and trying to figure out the architecture and mechanism of this.
EDIT: please post tested versions of the code, as some of em' posted below DO NOT update in real time
Try this Example
Hope it will work for u
JS
for(i = 1; i <= 3; i++)
{
(function(i){
setTimeout(function(){
alert(i);
}, 1000 * i);
}(i));
}
Javascript operates synchronously in the browser.
You need to use setTimeout or setInterval to schedule the for loop's body to be called every second. I'm using setTimeout in the below example for easier "garbage collection"; we will never reschedule the tick to happen after we don't need to update things anymore.
<script type="text/javascript">
var counter = 0;
function counter_tick() {
if(counter < 60) {
counter++;
document.getElementById("counter").innerHTML = counter;
setTimeout(counter_tick, 1000); // Schedule next tick.
}
}
function counter_start() {
counter_tick(); // First update, also schedules next tick to happen.
}
</script>
It sounds like you are looking for a way to pause the current thread, which isn't possible in JavaScript and would probably be a bad idea anyway (the user's browser would lock up while the thread was paused).
A timer is really the way to go with this, otherwise you are fighting the way the language is intended to work.
There is no sleep-function in JS. But you can use window.setTimeout to call a function in given intervals:
function counter_start(){
// get current value
var value = document.getElementById("counter").innerHTML*1;
// leave function if 60 is reached
if(value == 60) {
return;
}
// set the innerHTML to the last value + 1
document.getElementById("counter").innerHTML=value+1;
// call next iteration
window.setTimeout(function(){counter_start()}, 100);
}
counter_start();
JSFiddle-Demo
For-loops run to completion, so you wouldn't usually use one for this.
You just need a timer and a variable to increment:
var maketimer = function(){
var tick = 0,
interval_ms = 1000,
limit = 10,
id;
return {
start: function(){
var timer = this;
console.log('start');
id = setInterval(function(){
if(tick === limit){
timer.stop();
timer.reset();
return;
}
tick += 1;
console.log(tick);
}, interval_ms);
},
stop: function(){
console.log('stop');
clearInterval(id);
},
reset: function(){
console.log('reset');
tick = 0;
}
};
};
var t = maketimer();
t.start();
If you really need to use a for-loop, then you could use a generator function. They're part of the proposed ES6 spec., and you'll need Firefox 26+ to try this out. However the only point of doing this would be to learn about generator functions.
var maketimer = function(){
var interval_ms = 1000,
limit = 10,
id,
loop,
it;
loop = function*(){
var i;
for(i=1; i<=limit; i+=1){
yield i;
}
};
it = loop();
return {
start: function(){
var timer = this;
console.log('start');
id = setInterval(function(){
var tick = it.next();
console.log(tick.value);
if(tick.done){
timer.stop();
timer.reset();
return;
}
}, interval_ms);
},
stop: function(){
console.log('stop');
clearInterval(id);
},
reset: function(){
console.log('reset');
it = loop();
}
};
};
var t = maketimer();
t.start();
Try this::
var x=0;
var myVar;
function myTimer() {
x++;
document.getElementById("counter").innerHTML = x;
if(x==60)
clearInterval(myVar);
}
function counter_start(){
myVar=setInterval(function(){myTimer()},1000);
}

Div value increment javascript

I am trying to make a div with an animated value increasing up to it's final value. Here's an example from themeforest: http://demo.themesvision.com/drupal/evolve/ (Happy customer, projects completed, etc)
I've tried lots of different code lines with no success. I was able to do the increment, but can't figure how to make a delay each time there's an increment. I've tried setTimeout() and setInterval().
Here's my code so far:
$(document).ready(function(){
test();
function test(){
var i = 0;
while ( i <= 100 ) {
$("#test").text(i);
i++;
}
}
});
Thank in advance!
for (var i = 0; i < 100; i++) { //For loop easier than while loop
setTimeout(function() { //SetTimeout
document.getElementById('test').textContent++; //...Where you increment the textContent
}, i * 20); //...At interval of 20ms
}
You need something like:
$(document).ready(function(){
var i = 0;
test();
function test(){
$("#test").text(i++);
if(i < 100) {
setTimeout(test, 500);
}
}
});

setInterval - How to preserve passed in variable

I did some digging around on SO and could not find exactly what I am trying to achieve.
In simplistic terms I have a function like
function(){
for(i=0;i<10;i++){
setInterval(function(){ alert(i);), 1000)
}
}
What I would expect is 10 setIntervals that would alert 1 to 10 every 1 second, what happens is it would alert 10 always since 'i' is 10 at the end of for loop. How do I pass 'i' to setInterval anonymous function so that I can preserve the value of i in setInterval?
Above was a simplistic version of my actual problem. I am actually trying to do this
var timers = [];
function(obj){
//Clear any intervals
for(i=0;i<timer.length;i++){
clearInterval(timers[i]);
}
// Empty timers Array
timers = [];
for(i in obj){
//My object from the dom. This guy is what I am trying to preserve
my_obj = document.getElementById(i);
if(obj[i] === "Something"){
timers.push(setInterval(function(){
my_obj.replace_class(["Something", "Otherthing"],"Something");
}, 1000)
}
}
}
my_obj in the above code always refers to id = last 'i' in obj.
Do I make sense?
This should do the trick ;)
for(i = 1; i < 11; i++){
(function(local_i){
setInterval(function(){ console.log(local_i); }, 1000 * local_i)
})(i);
}
You must capture the variable in a closure. In your case this is
function capture(x) {
setInterval(function () {
console.log(x);
}, 1000);
}
for (var i = 0; i < 10; i++) {
capture(i);
}
or
function capture(my_obj) {
var id = setInterval(function() {
my_obj.replace_class(["Something", "Otherthing"],"Something");
}, 1000);
return id;
}
for (i in obj) {
//My object from the dom. This guy is what I am trying to preserve
my_obj = document.getElementById(i);
if (obj[i] === "Something") {
timers.push(capture(my_obj));
}
}

Can't manage to sleep inside a loop

I want to pause 1 second for every time it loops, it is usually easy to do similar pauses on other cases, but when working with loops, it seems it get harder:
for (var i=0 ; i < 10 ; i++) {
document.write (i + "<br>");
// I want to wait 1 second here
}
This is one example of my thousands failed attempts:
function writeMsg (index) {
document.write (index + "<br>");
}
for (var i=0 ; i < 10 ; i++) {
setTimeout (writeMsg(i), 1000);
}
Any ideas of how to get this to work?
This function works more like a normal for loop while it isn't
You need to take into account that a for gets 3 arguments inbetween semicolons.
Before starting (ie var i=0 you define a variable)
A condition before running the code again (ie i < 10 while i is under 10)
An action everytime it finishes the code again (i++ add one to i)
Code
(function() {
// Define a variable
var i = 0,
action = function() {
// Condition to run again
if (i < 10) {
document.write(i + "<br>");
// Add one to i
i++;
setTimeout(action, 1000);
}
};
setTimeout(action, 1000);
})();
Here is a jsfiddle for this code demonstrating its working:
http://jsfiddle.net/sg3s/n9BNQ/
You pass the return value of a function call to setTimeout instead of a function. Try the following code:
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() {
writeMsg(i);
}, 1000*i);
})(i);
}
In case you wonder why the call is wrapped inside an anonymous function: Without that function each setTimeout callback would receive the same i so when the callbacks fire it would always be 10. The anonymous function creates a new i inside that is not connected to the loop variable.
Classic function-in-a-loop problem. One archetypal solution:
function createCallback(i) {
return function () {
writeMsg(i);
};
}
function writeMsg (index) {
document.write (index + "<br>");
}
for (var i=0 ; i < 10 ; i++) {
setTimeout (createCallback(i), 1000*i);
}
The 10 timeouts are all based on the time that setTimeout() is called. So, they are all triggered at the same time.
for (var i=0; i < 10; i++) {
(function(idx){
setTimeout(function(){
document.write(idx+"<br/>");
},1000*idx);
})(i);
};
try this it will definitely help who all are think how to make it work wait property inside For Loop...
try this code in this URL http://www.shopjustice.com/the-collections/C-10329.
var var2;
var tmp;
var evt;
var i=0;
var res = document.getElementsByClassName('mar-plp-filter-content nav nav--stacked')[0].children.length;
tmp = document.getElementsByClassName('mar-plp-filter-content nav nav--stacked')[0].children;
function myfunc()
{
if(i<res)
{
var2 = tmp[i].getElementsByTagName("span")[0].getElementsByClassName("inverted")[0];
// alert(var2.innerHTML);
var evObj = document.createEvent('MouseEvents');
evObj.initEvent( 'mouseover', true, false );
var2.dispatchEvent(evObj);
var2.style.backgroundColor="GREEN";
i++;
setTimeout(myfunc,3000);
}
};
setTimeout(myfunc,3000);

Categories