Cycle through an array an unlimited number of times using a combination of forEach and setTimeout

In my myClass, I am facing an issue with the method. When it reaches the end of the array, instead of starting over from 0, it simply stops.

this.jsonParse = function() {
    for (var i = 0; i < this.numberOfPhotos; i++){
         (function(index, selector, timing, arrayLength){
            setTimeout(function() {
               $(selector).css('background-color': obj_gallery.images[index].hex);
            }, index*timing);            
         })(i, this.slideWrap, this.timing,this.numberOfPhotos);
    }
}

I attempted to solve it with the following code snippet, but unfortunately, it did not work as expected.

if (index >= arrayLength) {
    index = 0;
}

Note: The local variables like this.numberOfPhotos have already been defined in earlier parts of the code.

Answer №1

It seems like your goal is to rotate images indefinitely, but your current method is quite inefficient. Running 1000 timers simultaneously and loading all 1000 images at once is not the best approach.

Instead, a simpler solution using a modulo operator on the index and a basic function to update gallery images can be implemented.

Here is a minimalistic HTML structure for the gallery:

<div id="gallery">
    <img id="gallery_a" onload="galleryLoaded()" />
    <img id="gallery_b" onload="galleryLoaded()" />
</div>

The `onload` events are utilized to switch the visible image once loaded and to ensure smooth transitions.

An example showcasing this approach can be found here on JSFiddle.

No special CSS is required except for setting up the transition effect for the second image:

#gallery_b {
    opacity: 0;
    transition: opacity 1s;
}

A function periodically called will update the image index and toggle between the two images:

// This function initializes the image switch
function galleryNext() {
    if (gallery_switching)
        return;

    gallery_switching = true;

    gallery_index = (gallery_index + 1) % images.length;

    document.getElementById(gallery_second ? 'gallery_a' : 'gallery_b').src = images[gallery_index];

    gallery_second = !gallery_second;
}

The `onload` event switches images when an image has finished loading:

// This function triggers after the next image has loaded
function galleryLoaded() {
    if (!gallery_switching)
        return;
    gallery_switching = false;

    document.getElementById('gallery_b').style.opacity = gallery_second ? 1 : 0;
}

To start the rotation interval and display the initial image immediately:

setTimeout(galleryNext, 0); // Placeholder "onload"
setInterval(galleryNext, 2500); // Switch every 5 seconds

You can also set the initial `src` for the image elsewhere in your code.

Answer №2

Instead of using incremental timeouts, I would recommend implementing a recursive approach for better efficiency. To start, it is advisable to create an abstraction that can be reused:

function iterateWithDelay(delay, callback, items) {
   var run = function(index) {
      setTimeout(function() {
         callback(items[index])
         index += 1
         if (index >= items.length) {
            index = 0
         }
         run(index)
      }, delay)
   }
  callback(items[0])
  run(1)
}

After defining this abstraction, you can apply it in the following manner:

this.jsonParser = function(){
    var $element = $(this.slideshowContainer)
    var changeBackgroundColor = function(image) {
        $element.css('background-color', image.colorCode)
    }
    iterateWithDelay(this.timeInterval, changeBackgroundColor, galleryObjects.images)     
};

Check out this DEMO for reference.

Answer №3

Check out this straightforward cycle function using Javascript Generator Functions. It draws inspiration from Ruby's Enumerable#cycle:

function* cycleArray(values) {
  let index = 0;
  let length = values.length;

  while (true) {
    yield values[index % length];
    index++;
  }
}

infiniteLoop = cycleArray(["x", "y", "z", true, false]);

console.log(infiniteLoop.next().value); // "x"
console.log(infiniteLoop.next().value); // "y"
console.log(infiniteLoop.next().value); // "z"
console.log(infiniteLoop.next().value); // true
console.log(infiniteLoop.next().value); // false

console.log(infiniteLoop.next().value); // "x"
console.log(infiniteLoop.next().value); // "y"
console.log(infiniteLoop.next().value); // "z"
console.log(infiniteLoop.next().value); // true
console.log(infiniteLoop.next().value); // false

console.log(infiniteLoop.next().value); // "x"
console.log(infiniteLoop.next().value); // "y"
console.log(infiniteLoop.next().value); // "z"
console.log(infiniteLoop.next().value); // true
console.log(infiniteLoop.next().value); // false

Answer №4

Consider using setInterval() instead of setTimeout - http://codepen.io/anon/pen/ogVodo

 this.jsonParse = function(){
  // An anonymous function is needed to pass parameters, as setTimeout does not do it.
  var slideWrap = this.slideWrap;
  var timing = this.timing;
  var numberOfPhotos = this.numberOfPhotos;
  var index =0;
  setInterval(function() {
     $(".gallery").css('background-color', obj_gallery.images[index].hex);
     index++;
     if (index === numberOfPhotos){
        index = 0;
     }
        },timing);            
  };

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Navigating between routes with React-router v4: A beginner's guide

There seems to be an issue with the routing functionality in my project. Currently, only the first component, Cloud, is being rendered on the / route. However, when I try to add other routes, they don't seem to work as expected. import React from &a ...

Enter the text div that has been chosen

I have a mini question regarding how to select text and place it in a selected div. This demo was created from codepen.io. In this demo, you will see a blue button and text in a textarea. I would like to be able to select the text "Select this text", cli ...

Adjust the font size based on the dimensions of the container

I'm currently working on a script that dynamically sets the font-size based on the container's dimensions and the length of the text. This is what I have implemented so far. window.onload = function () { var defaultDimensions = 300; ...

Is there a way to utilize a JavaScript function to transfer several chosen values from a select listbox to a different listbox when a button is clicked?

Is it possible to create a functionality where users can select multiple values from a first list and by clicking a button, those selected values are added to a second list? How can this be achieved through JavaScript? function Add() { //function here ...

Unable to retrieve information using the post method in Express framework

After creating a basic code to fetch data from the client, I am facing an issue where req.body.firstname is showing as undefined. Here is the code snippet: const express = require('express'); const app = express(); const body ...

encountering a problem while trying to run `npm install react-native-modal-datetime-picker` in the terminal

I've encountered an issue while working on my app where I keep getting errors when trying to install the react-native-modal-datetime-picker package, as well as other date time picker packages like @react-native-community/datetime-picker The specific ...

Pytest is not able to locate any elements on the webpage, yet the same elements can be easily found using the console

When using CSS or XPath in the console (F12), I am able to locate the element on the page. $$("span.menu-item[data-vars-category-name='Most Popular']") However, when trying to find the same elements with Selenium (pytest) using: driver.find_el ...

Adjusting the margin to center vertical content dynamically

I have encountered a perplexing situation with my layout. In the design below, you can see both double-lined and single-lined text. I have set a margin for the single-lined texts to align them properly. However, when it comes to double-lined text, I find m ...

In JavaScript, merging objects will exclusively result in an identifier being returned

When working with mongoose, I have encountered an issue where combining data from multiple finds only displays the id instead of the entire object. Interestingly, when I use console.log() on the object directly, it shows all the contents. Below are snippe ...

The process of sharing information between JavaScript classes

I'm struggling to grasp the concept of object-oriented JavaScript, particularly in terms of how classes can communicate with each other. Let's consider an example using Babel: We have a "ColorPalette" class that contains a list of colors We also ...

Populate your website with both a Bootstrap Popover and Modal for interactive user engagement through hover

Here's the situation: I want to showcase a user's name with a popover that reveals a snippet of their profile information. I've got that part down, where it dynamically generates and displays the popover content as needed. The popover functi ...

The subsequent promise does not fire after the initial promise

Currently, I am developing a microcontroller that has the ability to accept docx files or html strings as input and convert them into a single pdf file. The converted pdf file link will then be returned as an output. This is the code snippet I have worked ...

Determining if a number exceeds 3 decimal points using AngularJS

I have encountered a problem where I need to determine if a value has more than three decimal places in AngularJS. Although I am familiar with checking if a value is a whole number or greater than zero, I am unsure how to perform this specific task. Below ...

What could possibly be causing a syntax error in my JavaScript code?

<script type="text/javascript> $(document).ready(function(){ $("a.grouped_elements").fancybox( 'transitionIn' : 'elastic', 'transitionOut' : 'elastic', 'speedIn' : 600, ...

Steps for adding a row as the penultimate row in a table

There aren't many solutions out there that don't rely on jQuery, but I'm looking to avoid it. The row content needs to be generated dynamically. Here is my flawed approach: function addRow() { let newRow = '<tr><td>B ...

Animation loading on React.js when the page or URL is changed

Just starting out with React and trying to incorporate a loading animation when the page/url changes on button click - check it out here: https://codesandbox.io/s/cthululel-7zmsl?fontsize=14 Successfully got the animation working on initial load, but runn ...

AngularJS - directive template is not being compiled correctly

I am facing an issue with AngularJS. .directive('field', ['$routeParams', function($routeParams){ return { restrict: 'E', compile: function(tElement, tAttributes) { var template ...

Generating custom perspectives of multi-dimensional arrays

In the realm of C++, I am currently tackling the task of creating a function to calculate marginal PDFs (Probability Density Functions). Essentially, this involves working with multi-dimensional data (PDF) defined across a grid of various variables. The pr ...

Empower the user with the ability to interact through touch on dynamically

I am trying to make a div touchable and draggable. I have dynamically created 1 to 10 divs within another div. Currently, these divs can only be dragged using the mouse or cursor. However, I want to enable dragging through touch as well. Can anyone provi ...

Bring div button on top of the contenteditable field

I am working on an Angular app for a client and need to implement a clickable button at the bottom right of a contenteditable element, similar to the image shown below : https://i.sstatic.net/J6XdW.png The challenge is that the content needs to be scroll ...