Why won't the below make the var i = 0 again and re-run through the loop?
for (var i = 0; i < menuitems.length; i++){
if (i == menuitems.length){
i = 0;
};
$(menuitems[i]).delay(3000*i).queue(function() {
$(this).trigger('click');
});
};
Because "i" will never be == to menuitems.length (in the body of the loop; it will be after the loop, of course). Your loop terminates as soon as "i" is not less than menuitems.length.
Because when i becomes menuitems.length, the for loop condition (i < menuitems.length) becomes false, so the loop stops.
Try this instead:
if (i == menuitems.length - 1){
But then, you'll need some way to make the loop stop; otherwise it will just keep going and freeze your browser.
This cannot work, because JavaScript code is not interruptible. Events like timer expirations will not be executed while you're inside the loop, so nobody from the outside will set an exit condition for you.
for (var i = 0;;i++)
{
i %= menuitems.length; // loops i when it exceeds list length
// the expiration of these delays will not interrupt the loop
$(menuitems[i]).delay(3000*i).queue(function() {
$(this).trigger('click');
});
// if you don't compute a break condition from within the loop, you're toast
if (some_break_condition) break;
}
Now if you want a scroller, the way to go is something like:
var timer;
var period = 1000; // milliseconds
function startScroll ()
{
stopScroll();
timer = window.setInterval(
move_something_around (), // do you scroll here
period);
}
function stopScroll ()
{
if (timer)
{
window.clearInterval(timer);
timer = null;
}
}
// html
<button type="button" onclick="startScroll()">Start</button>
<button type="button" onclick="stopScroll()" >Stop </button>
I ended up getting around this issue using the below code:
$('#scroll').click(function(){
setInterval(function(){
var u = 0;
document.getElementById('maps').setAttribute('src',myUrlArray[u]);
if(u < myUrlArray.length){
++u;
}else{
u = 0;
}
},3000);
});
My question ended up being very similar to this one:
JavaScript: Change iFrame src from Array
Related
I have to create a slideshow, using an array of images and have that set on a timer. There is a drop-down menu with slow, medium, and fast options and the pictures need to transition with accordance to the drop down option selected. Whenever I execute this code in a web browser the code repeats itself, while doubling, as I read the value of i in the console.
I have tried using a while and a do-while loop to have the images on a rotation.
I have also tried putting the if-statements outside and below/above the function.
<script>
var i = 0;
function changeImg(){
if (x == 'slow'){
setInterval("changeImg()", 5000);
} else if (x == 'medium'){
setInterval("changeImg()", 3000);
} else if (x == 'fast') {
setInterval("changeImg()", 1000);
} else {}
while (i < 3){
console.log(i);
document.slide.src = sportsArray[i];
i++;
}
console.log(i);
console.log(sportsArray);
}
</sctipt>
First, I would read up on MDN's docs on setInterval() and clearInterval to fill in the knowledge gaps that lead you to approach the problem this way.
You are recursively calling changeImg() in your code which I believe is causing the issue you describe as:
the code repeats itself, while doubling, as I read the value of i in the console
Also, your while loop will run immediately when calling changeImg() which also does not appear to be desired in this situation.
setInterval() mimics a while loop by nature. There is no need for a while loop in this code. Below is a solution that I hope you can use as a reference. I separated the code to determine the interval into a function the getIntervalSpeed.
function changeImg(x) {
var getIntervalSpeed = function(x) {
if (x === 'slow') {
return 5000;
} else if (x === 'medium') {
return 3000;
} else if (x === 'fast') {
return 1000;
} else {
return 3000;
// return a default interval if x is not defined
}
};
var i = 0;
var slideShow = setInterval(function() {
if (i >= sportsArray.length) {
i = 0; // reset index
}
document.slide.src = sportsArray[i]; // set the slide.src to the current index
i++; // increment index
}, getIntervalSpeed(x));
// on click of ANY button on the page, stop the slideshow
document.querySelector('button').addEventListener('click', function() {
clearInterval(slideShow);
});
}
I'm using a loop with window.open inside it, and I'm looking for a way to wait for the previous window to be closed before launching the next one.
for(...){
window.open('index.html', '_blank', 'nodeIntegration=yes');
Simple for loop will not work. This can be achieved by setInterval.
Please refer the code below.
var MyWin = null;//window obejct will assign in future
var i = 0;//Strating index of loop
var len = 5;//length of loop
var myInterval = setInterval(function () {
if ((!MyWin || MyWin.closed) && i < len) {
MyWin = window.open("http://www.google.com/");
i++;
}
else if (i >= len) {
clearInterval(myInterval);//dont forget to clear interval
}
}, 100);
I am new to javascript, my background is python and ruby and I am having issues dealing with javascript anonymous functions, my problem is the following:
I have an element in the page which has an attribute value (true/false), I need to keep performing an action until this attribute changes value.
the code that I tried out is below, as you could guess, the break won't quit the loop if result.value == true... Any idea if I am in the right direction?
var counter = 0;
while (counter < 5) {
this
.click('#someelementid')
counter++;
this
.getAttribute('#someelementid', 'disabled', function(result) {
if (result.value == 'true') {
this.break;
}
}.bind(this));
this.api.pause(1000);
};
My assumption is that by binding this, I have access to the while block? Please correct me if I am wrong.
Have you tried changing your code to something like below ?
var counter = 0;
var arr = [1, 2, 3, 4, 5];
while (counter < 5) {
arr.forEach(
(element) => {
if (counter < 5) { // if you don't have this it will print all 5, else it prints only 3
console.log('Element value:', element);
}
if (element == 3) {
counter = 5;
}
}
);
}
What happens is this:
When you enter the while loop it will enter the forEach loop and start iterating, when it reaches element == 3 it will set counter to 5, but it still has to finish the current forEach loop, once it does it wont perform another while loop therefore exiting it.
So changing your code to:
var counter = 0;
while (counter < 5) {
this
.click('#someelementid')
counter++;
this
.getAttribute('#someelementid', 'disabled', function(result) {
if (result.value == 'true') {
counter = 5; // This should do the trick (without 'this')
}
}.bind(this));
this.api.pause(1000);
};
The break inside a function would not break the loop outside the function.
Through getAttribute() get the result inline instead of having a callback. then you can break the function.
Or
Have a global variable. breakLoop = false; set it to true; inside the callback function. And put a check on this variable in the while loop. while(!breakLoop ..)
Another approach.
Don't have a loop altogether.
var counter = 0;
function doSomething(){
this.click('#someelementid');
counter++;
this.getAttribute('#someelementid', 'disabled', function(result) {
if(result.value != 'true' && counter<5){
this.api.pause(1000);
doSomething();
}
}.bind(this);
};
I am new to coding and I want to built a Text Adeventure Game with HTML , CSS and Javascript. I want to show many peaces of text from an array with a certain time between each text. I tried different methods to avoid an infinite loop because of setTimeout, but I didn't figure out how to apply it on my code.
Here's my code, that causes the crash:
var iCounterText = 0;
var verzog = function() {
document.getElementById('toggleText').insertAdjacentHTML('beforeBegin', '<br>--------------<br>');
document.getElementById('toggleText').insertAdjacentHTML('beforeBegin', part1[iCounterText]);
iCounterText = iCounterText + 1;
playaudio();
}
function forwardingLinks() {
while (iCounterText < part1.length - 1) {
setTimeout(verzog, 500); // Here is the problem //
}
document.getElementById('buttonLinks').innerHTML = part1[part1.length - 1];
}
The following code works fine, but then there is no timeout between the text:
function forwardingLinks() {
while (iCounterText < part1.length - 1) {
verzog();
}
document.getElementById('buttonLinks').innerHTML = part1[part1.length - 1];
}
Edit:
This is my new code with "setInterval". Problem: Value is added by 1, but the function is not using the part2 Array. Instead it is using part1 Array again, although the partvalue already contains part2 array.
var part1 = [ //Texte und Antworten
'Hallo?',
'Test?',
'What',
'hello',
'--------------',
'Was?'
];
var part2 = [ //Texte und Antworten
'part2 goes on....',
'bla bla',
'blablabla'
];
var iCounterText = 0;
var value = 1;
var partvalue = eval("part" + value);
function forwardingLinks() {
var verzog = setInterval(function(){
if(iCounterText < partvalue.length-2){
++iCounterText;
toggleText.insertAdjacentHTML('beforeBegin', '<br>--------------<br>');
toggleText.insertAdjacentHTML('beforeBegin', partvalue[iCounterText]);
playaudio();
}else{
buttonLinks.innerHTML = partvalue[partvalue.length-1];
++value;
iCounterText=0;
clearInterval(verzog);
}
},500);
}
You are misunderstanding the flow of your while loop. JavaScript runs in a single-threaded environment. That means that your calls to the verzog function won't run until the forwardingLinks function completes, but your forwardingLinks function won't ever complete because you have a while loop that is dependent on a counter that is never increased, because verzog hasn't run yet.
Change your while loop, so that the iCounterText variable gets incremented from within the loop, so the loop can end and then the calls to verzog that have stacked up in the event queue can start to run.
Additionally, since you are using a numeric counter, a regular for loop would be better than an while loop because the loop's step value (++iCounterText) is required:
for(var iCounterText = 0; iCounterText < part1.length; ++iCounterText) {
setTimeout(verzog, 500);
}
As an aside from your main problem, it is very inefficient to repeatedly scan the DOM for the same element over and over, as you are doing in your verzog function. Instead, just get the DOM reference once and store it in a variable that can be reused:
// Declare a variable in a scope that is accessible throughout your code
var toggleText = null, buttonLinks = null;
// Set up a callback that runs after the DOM is ready
window.addEventListener("DOMContentLoaded", function(){
// Scan the DOM for the element(s) you'll be needing
toggleText = document.getElementById('toggleText');
buttonLinks = document.getElementById('buttonLinks');
});
function verzog() {
// Now, you can just refer to the DOM element you've already found:
toggleText .insertAdjacentHTML('beforeBegin', '<br>--------------<br>');
toggleText .insertAdjacentHTML('beforeBegin', part1[iCounterText]);
playaudio();
}
function forwardingLinks() {
for(var iCounterText = 0; iCounterText < part1.length; ++iCounterText) {
setTimeout(verzog, 500);
}
// Now, you can just refer to the DOM element you've already found:
buttonLinks.innerHTML = part1[part1.length - 1];
}
I have an array called RotatorNames. It contains random things but let's just say that it contains ["rotatorA","rotatorB","rotatorC"].
I want to loop through the array, and for each item i want to trigger a click event. I have got some of this working, except that the everything get's triggered instantly. How can i force the loop to wait a few seconds before it continues looping.
Here's what i have.
function Rotator() {
var RotatorNames = ["rotatorA","rotatorB","rotatorC"];
RotatorNames.forEach(function(entry){
window.setTimeout(function() {
//Trigger that elements button.
var elemntBtn = $('#btn_' + entry);
elemntBtn.trigger('click');
}, 5000);
});
}
You can run this to see what my issue is. http://jsfiddle.net/BxDtp/
Also, sometimes the alerts do A,C,B instead of A,B,C.
While I'm sure the other answers work, I would prefer using this setup:
function rotator(arr) {
var iterator = function (index) {
if (index >= arr.length) {
index = 0;
}
console.log(arr[index]);
setTimeout(function () {
iterator(++index);
}, 1500);
};
iterator(0);
};
rotator(["rotatorA", "rotatorB", "rotatorC"]);
DEMO: http://jsfiddle.net/BxDtp/4/
It just seems more logical to me than trying to get the iterations to line up correctly by passing the "correct" value to setTimeout.
This allows for the array to be continually iterated over, in order. If you want it to stop after going through it once, change index = 0; to return;.
You can increase the timeout based on the current index:
RotatorNames.forEach(function(entry, i) {
window.setTimeout(function() {
//Trigger that elements button.
var elemntBtn = $('#btn_' + entry);
elemntBtn.trigger('click');
}, 5000 + (i * 1000)); // wait for 5 seconds + 1 more per element
});
Try:
var idx = 0;
function Rotator() {
var RotatorNames = ["rotatorA", "rotatorB", "rotatorC"];
setTimeout(function () {
console.log(RotatorNames[idx]);
idx = (idx<RotatorNames.length-1) ? idx+1:idx=0;
Rotator();
}, 5000);
}
Rotator();
jsFiddle example
(note that I used console.log instead of alert)
Something like this should do what you're after:
function Rotator(index){
var RotatorNames = ["rotatorA","rotatorB","rotatorC"];
index = (index === undefined ? 0 : index);
var $btn = $("#btn_"+RotatorNames[index]);
$btn.click();
if(RotatorNames[index+1]!==undefined){
window.setTimeout(function(){
Rotator(index+1);
}, 500);
}
}