Jay
Jay

Reputation: 5074

Javascript Loop through Array while displaying the elements

I want to create a 'random selector' behaviour where the function iterates through an array for a period of time (example: 3 seconds, 5 seconds) while displaying all of array elements fast throughout the iteration until the iteration ends. Just imagine seeing all the elements displayed in a label one after another until it finally stops at an element.

My code so far:

var places = ["Curry Leaf", "Subway", "Burger King"];

function execute_randomizer() {
    var place_label = document.getElementById("place_label");
    for (var i = 0; i < 100; i++) {
        var selected_place = places[Math.floor(Math.random() * places.length)];
        setTimeout(function () {
            place_label.innerText = selected_place;
        }, 400);
    }
}

This runs through the iteration and displays an element when the loop is done but it doesn't show each iteration's element. How can I amend this?

EDIT

Even if there's 3 elements, the animations must re-iterate through the array until the duration is completed

Upvotes: 0

Views: 915

Answers (4)

Nina Scholz
Nina Scholz

Reputation: 386540

You could use a closure over the value and a different time for each timeout.

var places = ["Curry Leaf", "Subway", "Burger King"];

function execute_randomizer() {
    var place_label = document.getElementById("place_label");
    for (var i = 0; i < 10; i++) {
        var selected_place = places[Math.floor(Math.random() * places.length)];
        setTimeout(function (value) {
            return function () {
                place_label.innerText = value;
            };
        }(selected_place), i * 100);
    }
}

execute_randomizer();
<div id="place_label"></div>

For a first run through, you could show each element and then take a random element at last value.

function execute_randomizer() {
    function cb (value) {
        return function () {
            place_label.innerText = value;
        };
    }

    var place_label = document.getElementById("place_label");

    place_label.innerText = '';
    for (var i = 0; i < places.length; i++) {
        setTimeout(cb(places[i]), 200 + i * 200);
    }
    setTimeout(cb(places[Math.floor(Math.random() * places.length)]), 200 + places.length * 200);
}

var places = ["Curry Leaf", "Subway", "Burger King"];

execute_randomizer();
<div id="place_label"></div>

Upvotes: 1

Dennis
Dennis

Reputation: 164

I think it might be better if you would put the whole function in a timeout. (I'm not sure and didn't test, but that's what I would try).

What I mean is that you just build a function that creates your randomizer and fills in your field. After that you put a timeout to call the same function again + keep a counter that you pass as parameter.

An example of what I mean below: (didn't test it)

var places = ["Curry Leaf", "Subway", "Burger King"];

execute_randomizer(0); /* Start for the first time */

function execute_randomizer(times) {
    if(times == 100)
        return; /* stop execution */

    var place_label = document.getElementById("place_label");
    var selected_place = places[Math.floor(Math.random() * places.length)];
    place_label.innerText = selected_place;
    setTimeout(function () {
        execute_randomizer(times+1)
    }, 400);
}

Upvotes: 0

Alexandru Severin
Alexandru Severin

Reputation: 6218

Your for finishes iterating before the setTimeout runs, then the function passed to setTimeout runs 100 times using the last value of selected_place.

More about this behavior in setTimeout in for-loop does not print consecutive values


Another problem that I noticed is that your setTimeout will trigger after 400ms, since the for loop will finish in about 1 ms, the function passed to setTimeout will trigger 100 times one after another with no delay in between, for this, I replaced the delay argument of setTimeout from 400 to 400 * i.


var places = ["Curry Leaf", "Subway", "Burger King"];     
function execute_randomizer() {
    var place_label = document.getElementById("place_label");
    for (var i = 0; i < 100; i++) {
        var selected_place = places[Math.floor(Math.random() * places.length)];
        (function(selected_place){
          setTimeout(function () {
              place_label.innerText = selected_place;
          }, 400 * i);
        })(selected_place);
    }
}
execute_randomizer();
<span id="place_label"></span>

Upvotes: 1

hsd
hsd

Reputation: 452

You should change your loop because right now you go in loop 100 times in maybe one millisecond and order 100 of change text but once again in the same time. So better is wait for time out 400 ms and then make next iteration. Please remember time out is async.

Upvotes: 0

Related Questions