JS setTimeout() function - javascript

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 ;)

Related

Making blocks visible/invisible using javascript

Here is my code.
var i = 0;
var submenues = document.getElementsByClassName("submenu");
var click = 1;
function submenuvisible() {
if (click == 1) {
for (i; i < submenues.length; i++) {
submenues[i].style.display = "block";
}
click = 2;
return;
}
if (click == 2) {
for (i; i < submenues.length; i++) {
submenues[i].style.display = "none";
}
click = 1;
return;
}
}
Though when i onclick=submenuvisible() it works only 1 time. What am I doing wrong?
Your mistake is in your for loops.
Where you have: for (i; i < submenues.length; i++) {
You need to reset the variable i to 0 at the beginning of the for loops.
for (i = 0; i < submenues.length; i++) {
If you don't reset it, then i will remain at the same value it was after the first time you run your function. You could improve your code further by not making i a global variable, but overall, I hope this explains your issue.

setTimeout within a for loop not executing the function passed to it

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

JavaScript / jQuery : restart for loop on last iteration

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

self executing anonymous click function in for loop

I need a click function in a for loop, so every id element is clickable. But I also need the i in the click function, that's why I thought a self executing anonymous function would be the best way to do so. But for some reason this is not working, maybe because the click function doesn't allow me to forward a parameter? What have I done wrong?
for (var i = 0; i < countItems; i++) {
$("#item-" + i).click(function(idx) {
alert(idx);
})(i)
}
The self executing function must return a function:
for (var i = 0; i < countItems; i++) {
$("#item-" + i).click(function(indx){
return function(){ //must return a function
alert(indx);
}
}(i));
}
JS Fiddle: http://jsfiddle.net/HuHXr/
As a side note, using bind() javascript method:
for (var i = 0; i < countItems; i++) {
$("#item-" + i).click(function(indx){
alert(indx);
}.bind($("#item-" + i)[0],i));
}
you can try something like this
for (var i = 0; i < countItems; i++) {
$("#item-" + i).click(clickFunctn);
}
function clickFunctn(obj){
var i=$(obj).attr('id').split('-')[1];
alert(i);
}
In this way you will optimize the code and your 'i' will be with you as well, and all items are clickable. And you are just binding one handler function.
for (var i = 0; i < countItems; i++) {
(function(i){
$("#item-" + i).click(function(idx) {
alert(idx);
});
})(i);
}
Also note that idx is the event object.
Fiddle: http://jsfiddle.net/2DRLx/

javascript function doesn't return any result

I've got a javascript function
<head>
<title>
Test
</title>
<script type="text/javascript">
function GetResult()
{
count = 0;
for(var i=0;i<10;i++){
for(var j=1;j<4;j++){
if (document.getElementById("label"+i+j).checked){
count +=1;
}
}
}
if (count!=10)
alert("Please answer all the questions");
else alert(count);
}
</script>
In the code there are a lot of radiobutton. ther look like
<input type="radio" name="q1" value="1" id="label01"/>
But my javascript function never shows alert.
The button that is supposed to call function is
<input type="button" value="Result" onclick="GetResult()"/>
Maybe button doesn't call GetResult?
To elaborate what Felix already said: Here is how you can check whether or not document.getElementById found the specified element (it will return null if it failed).
for (var i = 0; i < 10; i++) {
for (var j = 1; j < 4; j++) {
// Store the result in a local variable
var label = document.getElementById("label"+i+j);
// Include a check whether "null" got returned
if (label && label.checked) {
count +=1;
}
}
}
Try this:
function GetResult() {
var count = 0;
for (var i = 0; i < 10; i++){
for (var j = 1; j < 4; j++){
var label = document.getElementById("label" + i + j);
if (label && label.checked) {
count +=1;
}
}
}
if (count != 10) {
alert("Не все отвечено");
} else {
alert(count);
}
}
Added var to the count declaration.
Fixed up some general formatting.
The important bit: checked to see if document.getElementById() returned a value before checking that value's checked property.

Categories