I am trying to make a for loop that starts over when it reaches the last iteration.
Here's what I have so far:
for (var i = 0; i < x + 3; i++) {
(function(i){
setTimeout(function(){
$('#e'+i).animate({'color': '#B2E4FF'}, 500);
var j = i - 3;
$('#e'+j).animate({'color': '#A6A5A6'}, 500);
}, 100 * i);
}(i));
if(i == x + 2) {
i = -1;
continue;
}
}
When I add continue; to the script, it stops working completely.
What I want to achieve with this is an animated sliding gradient text. DEMO 1 LOOP: http://puu.sh/aCzrv/98d0368e6b.mp4
Full Code: http://jsfiddle.net/D6xCe/
Regards,
Alex
Dont abuse the for loop.
Use a while loop for that.
var isCompleted = false;
while(!isCompleted){
// do logic and when completed assign isCompleted = true;
}
Edit
Due to your request, it should look something like this:
var isCompleted = false;
var i = 0;
while (!isCompleted) {
(function (i) {
setTimeout(function () {
$('#e' + i).animate({
'color': '#B2E4FF'
}, 500);
var j = i - 3;
$('#e' + j).animate({
'color': '#A6A5A6'
}, 500);
}, 100 * i);
}(i));
if (i == x + 2) {
i = 0;
} else if (i == x + 3) {
isCompleted = true;
}
i++;
}
There is a problem with your code
You say that if i < x+3 -> break the loop and if i == x+2 -> reset the index and start again.
Since i is incremented by 1 on each iteration, you are trying to perform an "infinite loop".
Use while(true) for that.
You will never get to the i == x+3 condition so you can remove it from the code I've added and get an infinite loop that does you logic based on resetting after x+2 iterations.
var i = 0;
while (true) {
(function (i) {
setTimeout(function () {
$('#e' + i).animate({
'color': '#B2E4FF'
}, 500);
var j = i - 3;
$('#e' + j).animate({
'color': '#A6A5A6'
}, 500);
}, 100 * i);
}(i));
i = i == x+2 ? 0 : i+1;
}
You can wrap animation code in function and repeat this function again after the loop is over:
function animate() {
for (var i = 0; i < x + 3; i++) {
(function (i) {
setTimeout(function () {
var j = i - 3;
$('#e' + i).animate({color: '#B2E4FF'}, 500);
$('#e' + j).animate({color: '#A6A5A6'}, 500, function() {
if (i == x + 2) {
animate();
}
});
}, 100 * i);
}(i));
}
}
animate();
Demo: http://jsfiddle.net/D6xCe/2/
if you want to perform a continues execution of certain statement just make an infinitive loop.There are many ways to form a infinitive loop the easiest way is to use while loop. eg:
while(true)
{
//your statements
}
thank you
Related
i just started to learn JS. I want to change my span tag's position with respect to time with JS setTimeout function. But it did not worked with this code. What am i doing wrong ?
function myFunction2() {
var j = 0;
document.getElementById("demo").style.left = j + "px";
j++;
}
function myFunction() {
var i = 0;
while (i <= 200) {
setTimeout(myFunction2, 20);
i++;
}
You need to declare j outside the function. Otherwise, you're always setting it to 0 every time the function is called.
Also, you're running all instances of the function at the same time, 20 ms after the loop. You should multiply the timeout by the loop index:
Full demo:
var j = 0;
function myFunction2() {
document.getElementById("demo").style.left = j + "px";
j++;
}
function myFunction() {
var i = 0;
while (i <= 200) {
setTimeout(myFunction2, 20 * i);
i++;
}
}
<span id="demo" style="position:absolute;left:0px;">Bu benim ilk paragrafım.</span><br> <button type="button" onclick="myFunction();">Try</button>
Or you could use setInterval() to run it repeatedly automatically.
function myFunction() {
var j = 0;
var int = setInterval(function() {
if (j > 200) {
clearInterval(int);
} else {
document.getElementById("demo").style.left = j + "px";
j++;
}
}, 20);
}
<span id="demo" style="position:absolute;left:0px;">Bu benim ilk paragrafım.</span><br> <button type="button" onclick="myFunction();">Try</button>
It seems like you are declare the J variable inside the function and set it to 0 every time. So every time when you call the function you're calling the timeout on same interval. And My solution is set the J Out side the function like a global variable and then try it.
var j = 0;
function myFunction2() {
document.getElementById("demo").style.left = j + "px";
j++;
}
function myFunction() {
for (var i = 0; i <= 200; i++) {
setTimeout(myFunction2, 20 * i);
}
}
It is not working because whenever you are calling myFunction2(), variable j is initialized with 0 again and technically you are assigning 0px to demo. So that's why it's not shifting.
As said , you need to declare j as a variable outside the function itself , then you eventually test it within the function .
I would use for (){} instead while () {}
here is another example :
let j;// declare j
function myFunction2() {
if (!j) {// has j already a value ?
j = 0;
}
document.getElementById("demo").style.left = j + "px";
j++; // now it has a value, it can be incremented from here anytime the function is called
}
function myFunction() {
for (let i = 0; i <= 200; i++) {
setTimeout(myFunction2, i * 20);// increment settimeout for each loop
}
}
#demo {
position: relative;
}
<div id="demo">test demo</div>
<button onclick="myFunction()">test myFunction</button>
Now, every time you call the function it increments the position of 200px away from lft. 1 click = 200px , 2click = 400px ;
Have fun coding ;)
i'm trying to make a "console typing effect" with js, and in the next function i take the text of an element, then i use a "for" loop for slicing that text and paste in within with a delay.
After debugging the code in chrome i can see that javascript doesn't run the setTimeout... it just ignores it.
function type() {
var text = document.querySelector('.console-effect').textContent;
for (var i = 0; i <= text.length; i++) {
setTimeout(function() {
document.querySelector('.console-effect').textContent = text.substr(0, i)
}, 50);
}
}
type();
Your setTimeouts are all executing at the same time, because the for loop does not wait for them to execute on each iteration. You have to delay each timeout using a value such as 50*i.
Then, to preserve the value of i in this case, you'll need to use a closure. Otherwise, by the time your timeouts come to an end, the loop will be over, and i will be the final value, for all of them.
var text = document.querySelector('.console-effect').textContent;
for (var i = 0; i <= text.length; i++) {
(function(i) {
setTimeout(function() {
document.querySelector('.console-effect').textContent = text.substr(0, i);
}, 50*i);
})(i);
}
body{background: #333;}
.console-effect{color: #0f0; font-family: monospace; font-size: 2em;}
<div class="console-effect">This is some example text</div>
Is not a good idea to make functions inside a loop in Javascript, I had bad experiences with it.
This code done this way should work correctly:
function type() {
var text = document.querySelector('.console-effect').textContent;
var loopFunc = function(i) {
return function() {
document.querySelector('.console-effect').textContent = text.substr(0, i)
};
};
for (var i = 0; i <= text.length; i++) {
setTimeout(loopFunc(i), 50);
}
}
type();
I didn't want to believe #blex, but he was correct about the scope. He was right on both points he made, but the closure stunned me. How have I never encountered this and been forced to puzzle my way out before?
So the idea here is that instead of scheduling a dozen or so calls to your function at the beginning, you only schedule the next call. After that one is called, it sees if it needs to schedule the next.
function type() {
var text = document.querySelector('.console-effect').textContent;
var i = 0;
var typeNext = function() {
++i;
document.querySelector('.console-effect').textContent = text.substr(0, i);
if(i < text.length) {
setTimeout(typeNext, 50);
}
}
setTimeout(typeNext, 50);
}
type();
<span class="console-effect">This is a test</span>
var text = document.querySelector('.console-effect').textContent;
var index = 0;
setInterval(function(){
document.querySelector('.console-effect').textContent = text.substr(0, index);
if(index == text.lenght){
clearInterval(this);
}
index++;
},1000);
Do something like this.
function type() {
var text = document.querySelector('.console-effect').textContent;
document.querySelector('.console-effect').textContent = '';//clear content
for (var i = 0; i <= text.length; i++) {
setTimeout(function(j) {
document.querySelector('.console-effect').textContent += text[j];// or .charAt(j)
}, 50 * i, i);
// 50 * i sets timeout for each iteration
// i (3rd arg) passes to the inner function
}
}
type();
Better version.
function type(text) {
var textObj = document.querySelector('.console-effect');
for (var i = 0; i <= text.length; i++) {
setTimeout(function(ch) {
textObj.textContent += ch;
}, 50 * i, text[i]);
// 50 * i sets timeout for each iteration
// i (3rd arg) passes to the inner function
}
}
type('.console-effect');
a solution without 50*i, take a look at the css effect too. You problem is setTimeout is executed asynchronously (the 'control flow' doesn't wait for those 50ms), so they are fired all together with value i = text.length (if your text is small enough)
<p class="console-effect">console effects</p>
<script>
function type() {
var i=0;
var t = document.querySelector('.console-effect').textContent;
var fn = setInterval(function() {
print_text(++i,t,fn)
}, 500);
}
function print_text(i,t,fn){
if(i <= t.length){
document.querySelector('.console-effect').textContent = t.substr(0, i)
} else clearInterval(fn)
}
type();
</script>
<style>
#-webkit-keyframes blinker {
from { opacity: 1.0; }
to { opacity: 0.0; }
}
.console-effect:after{
content:'_';
text-decoration: blink;
-webkit-animation-name: blinker;
-webkit-animation-duration: 0.2s;
-webkit-animation-iteration-count:infinite;
-webkit-animation-timing-function:ease-in-out;
-webkit-animation-direction: alternate;
}
</style>
setTimeout run only once(in your case after delay of 50ms).
For this purpose you should use setInterval
I'm using some code like this
window.setInterval(function(){
//Code goes here
}, 3000);
for a 3 seconds loop, and I want to have a timer counting up within that that updates every seconds instead of every 3 seconds, is that possible?
I tried putting this in the loop:
var stmints = 0;
var stseconds = 0;
var stzecsec = 0;
function toAutoStop() {
alert('Your life goes on');
}
var zecsec = 0;
var seconds = 0;
var mints = 0;
var startchron = 0;
function chronometer() {
if(startchron == 1) {
zecsec += 1; // set tenths of a second
if(zecsec > 9) {
zecsec = 0;
seconds += 1;
}
if(seconds > 59) {
seconds = 0;
mints += 1;
}
document.getElementById('showtm').innerHTML = mints+ ' : '+ seconds+ '<sub>'+ zecsec+ '</sub>';
if(zecsec == stzecsec && seconds == stseconds && mints == stmints) toAutoStop();
else setTimeout("chronometer()", 100);
}
}
function startChr() { startchron = 1; chronometer(); } // starts the chronometer
function stopChr() { startchron = 0; } // stops the chronometer
function resetChr() {
zecsec = 0; seconds = 0; mints = 0; startchron = 0;
document.getElementById('showtm').innerHTML = mints+ ' : '+ seconds+ '<sub>'+ zecsec+ '</sub>';
}
startChr();
You may want to make your period 1s then:
var UPDATE_PERIOD = 1;
var ACTION_PERIOD = 3 * UPDATE_PERIOD;
var passed = 0;
setInterval(function() {
passed += UPDATE_PERIOD;
updateTimer();
if(passed % ACTION_PERIOD === 0) {
doStuff();
}
}, UPDATE_PERIOD * 1000);
function updateTimer() {
document.getElementById("timer").textContent = "" + passed + "s";
}
function doStuff() {
// do your stuff here
}
Very simple example: http://jsbin.com/aSAQiYud/1/edit
http://jsfiddle.net/459Lt/
this is actually very easy. I used jquery but that's for just selecting elements. Nothing truly that controls logic.
w.clone().appendTo('body'); is where you would like to put function that needs to be called... like dowork().....
var t=0, w=$('.w'),txt=$('.text');
setInterval(f,1000);
function f(){
txt.text(t+1);
if(t==2) w.clone().appendTo('body');
t=++t%3;
}
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 9 years ago.
The following code creates 10 elements under <body id="container" />. When i click on any element, I always see an alert with the value 10.
How can I get each alert to show the index of each element?
for (var i = 0; i < 10; ++i) {
var id = "#element_" + i;
$("#container").append('<p id="element_' + i + '">foo</p>');
$(id).click(function (e) {
alert(i);
});
}
You need either closure or simply use $.on() with data:
for (var i = 0; i < 10; ++i) {
var id = "#element_" + i;
$("#container").append('<p id="element_' + i + '">foo</p>');
$(id).on("click", i, function (e) { alert(e.data); });
}
Don't make functions inside for loops
for (var i = 0; i < 10; ++i) {
$("#container").append('<p id="element_' + i + '">foo</p>');
}
$("#container > p").click(function (e) {
var idNum = this.id.split('_')[1];
alert(idNum); // 0, 1, 2 ...
});
DEMO
need to create a private closure
for (var i = 0; i < 10; ++i) {
(function(idx){
var id = "#element_" + idx;
$("#container").append('<p id="element_' + idx + '">foo</p>');
$(id).click(function (e) {
alert(idx);
});
})(i)
}
Demo: Plunker
I have a JSON object of the format:
{
"z061": {
"status": "restored",
"time": 135
},
"z039": {
"status": "restored",
"time": 139
}, ...
}
where there are 64 zones numbered z001 to z064.
What is the best way in Javascript to populate a table based on the "status" of zones z001 to z015? Here is my current code that only evaluates zone z003:
setInterval(function() {
$.getJSON("http://rackserver.local:8080",function(data) {
var temp = data.z003.status;
if (temp != "restored")
$("#securityTable tr:eq(3)").removeClass("error").addClass("success");
else
$("#securityTable tr:eq(3)").removeClass("success").addClass("error");
});
}, 1500);
You can access objects with the dot operator or with the indexers operator, this task is for the indexers.
for (var i = 1; i <=15; i++){
// hardcoded the check to make it easier.
if (i >= 10)
var temp = data["z0" + i].status;
else
var temp = data["z00" + i].status;
}
$.getJSON("http://rackserver.local:8080",function(data) {
$.each( data, function( key, value ) {
if (data[key].status != "restored") {
//do your stuff
} else {
//do more stuff
}
});
Here is the code I came up with.
setInterval(function() {
$.getJSON("http://rackserver.local:8080",function(data) {
var i = 1, j;
for (; i <= 64; i += 1) {
j = 'z';
if (i < 10) j += '0';
if (i < 100) j += '0';
if (data[j + i].status !== "restored")
$("#securityTable tr:eq(" + i + ")").removeClass("error").addClass("success");
else
$("#securityTable tr:eq(" + i + ")").removeClass("success").addClass("error");
}
}, 1500);
Hope this helps.