Using Typescript to set a custom timeout duration based on a dynamic variable within a for loop

My function includes a timeout that changes every 3 seconds:

 setActiveImage(promotions) {
    for (let i = 0; i <= promotions.length - 1; i++) {
      setTimeout(()=> {
        this.activeImage = 'http://myrul/public/Commercials/' + promotions[i].commercial_file[0].file;
      }, 3000*(i)); //CHANGE PICTURE EVERY 3s

    }
  }

Now, I want to replace the fixed time (3000) with a variable obtained from promotions. Here is the relevant information from https://i.sstatic.net/CbKdG.png

Each picture, or instance of i, should have its own specific time duration.

Here is my attempt:

for (let i = 0; i <= promotions.length - 1; i++) {

  var x = promotions[i].time; //GET TIME
  var y = +x; //TURN STRING TO NUMBER
  var z = y * 1000; //TURN SECOND INTO MILISECONDS

  var promoDisplayTime = z; //CUSTOM TIME

  setTimeout(()=> {
    this.activeImage = 'http://myurl/Commercials/' + promotions[i].commercial_file[0].file;
  }, promoDisplayTime*(i));

}

Despite using the correct variable promoDisplayTime, the timer seems to be inaccurate. For instance, the first picture should last 4 seconds, but it only lasts 3 seconds. The second picture should be displayed for 3 seconds, but it lasts 6 seconds. The third picture should be shown for 10 seconds, but it only lasts 4 seconds...

I am unsure of what I am doing wrong. Why is the timer off even with the correct time value?


For a demonstration with dummy data, please visit this StackBlitz link

Answer №1

Below is a potential solution using the async function in conjunction with setTimeout().

By utilizing an async function, we ensure that the subsequent slide is not triggered until the previous one has completed.

It is important to note that with setTimeout, the function will be executed after the specified time has elapsed.

Here is an example of how this can be implemented:

activeImage: string = 'https://pngimage.net/wp-content/uploads/2018/06/start-png-.png';

  promotions = [
    {
      time: 6,
      pic: 'https://pngimage.net/wp-content/uploads/2018/06/1-an-png-1.png'
    },
    {
      time: 3,
      pic: 'https://upload.wikimedia.org/wikipedia/commons/1/10/MRT_Singapore_Destination_2.png'
    },
    {
      time: 4,
      pic: 'https://upload.wikimedia.org/wikipedia/commons/a/aa/L%C3%ADnea_3_CAMETRO.png'
    }
  ];

  ngOnInit() {
      this.setActiveImage();
  }

  setActiveImage() {
    let _this = this;
    countDown();

    function displayImage(i) {

      return new Promise(resolve => {
        _this.activeImage = _this.promotions[i].pic;
        setTimeout(function () {
          resolve(true);
        }, _this.promotions[i].time * 1000);
      });
    }

    async function countDown() {
      for (var i = _this.promotions.length -1; i >= 0; i--) {
        await displayImage(i);
      }
    }

  }

Check out the live demo: https://stackblitz.com/edit/angular-qwtgm2

Answer №2

I have identified a couple of errors:

  1. The first mistake is counting i starting from 0. This causes the initial value (6 seconds) to be calculated as 0, resulting in the first function being executed almost immediately. Subsequently, the second value (3 seconds) is used to display the second picture, but it is multiplied by i, which is 1 at that moment (causing the first picture to last for 3 seconds). The logic repeats for the third picture.

  2. The second mistake is calling all setTimeout functions simultaneously, using i as a separator. To achieve the desired outcome, you should call setTimeout for picture n + 1 after the setTimeout for picture n has finished.

Answer №3

According to this response Is setTimeout the right choice for handling asynchronous functions in JavaScript?

setTimeout(function(){...}, 0) actually schedules the code to execute once the current call stack has been cleared.

What happens is that the for loop completes with promotions[i].time = 4 and the setTimeout function executes using that value (as observed in the code on StackBlitz)...

Answer №4

When working with Angular, I suggest harnessing the capabilities of RxJs.

const MOCK_DATA = [
  {
    time: "6",
    pic: "https://pngimage.net/wp-content/uploads/2018/06/1-an-png-1.png"
  },
  {
    time: "3",
    pic:
      "https://upload.wikimedia.org/wikipedia/commons/1/10/MRT_Singapore_Destination_2.png"
  },
  {
    time: "4",
    pic:
      "https://upload.wikimedia.org/wikipedia/commons/a/aa/L%C3%ADnea_3_CAMETRO.png"
  }
];

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  promotions$ = from(MOCK_DATA).pipe(
    map(promo => of(promo.pic).pipe(delay(1000 * +promo.time))),
    mergeAll(),
    startWith("https://pngimage.net/wp-content/uploads/2018/06/start-png-.png")
  );
}

And in your template:

<img [src]="promotions$ | async" alt="Responsive image of item">

Check out the live demo: https://stackblitz.com/edit/angular-xjcrgd?file=src/app/app.component.ts

Update: Considering the relative time in your question, you can create a function to convert to absolute time like this:

const convertToAbsoluteTime = (data: ServerContent[]): LocalContent[] =>
  data.reduce((acc, x) => {
    if (!acc.length) {
      acc.push({
        ...x,
        time: +x.time
      });
    } else {
      acc.push({
        ...x,
        time: acc[acc.length - 1].time + +x.time
      });
    }

    return acc;
  }, []);

This would result in photos being ordered 1, 2, 3.

Live demo: https://stackblitz.com/edit/angular-6c4pqt?file=src/app/app.component.ts

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

Return a string to the client from an express post route

I'm attempting to return a dynamically generated string back to the client from an Express post route. Within the backend, I've set up a post route: router.post('/', async (req, res) => { try { // Here, I perform computations on ...

Convert file_get_contents from PHP to JavaScript

I previously developed a webpage using php along with a webAPI, but now I am looking to transition it to javascript. The issue at hand: The current site takes about 5-7 seconds to load due to loading a large amount of data, which is not ideal. I want to ...

Encountering Compilation Issues Post Upgrading to Angular 9

I recently upgraded my Angular application from version 8 to version 9, following the official guide. However, after the upgrade, I encountered errors that prevent my application from building. The specific errors include: "Module not found: Error: Can ...

Using the async pipe on the MatTable datasource does not result in sorting functionality, but the table contents are updated correctly

I am encountering an issue with my MatTable that is not sorting when one of the headings are clicked, even though the arrow icon appears. The data loads and refreshes correctly when changes are made to the underlying data, but sorting seems to be a challen ...

What is the process for transforming binary code into a downloadable file format?

Upon receiving a binary response from the backend containing the filename and its corresponding download type, the following code snippet illustrates the data: 01 00 00 00 78 02 00 00 6c 02 00 00 91 16 a2 3d ....x...l....... 9d e3 a6 4d 8a 4b b4 38 77 bc b ...

Exploring the benefits of utilizing useState and localStorage in Next.js with server-side

Encountering an error consistently in the code snippet below: "localstorage is not defined" It seems like this issue arises because next.js attempts to render the page on the server. I made an attempt to place the const [advancedMode, setAdvanced ...

Encountering an issue while trying to install font-awesome in an Angular project

Encountering an error while trying to install font-awesome in angular npm install --save @fortawesome/fontawesome-free npm ERR! code UNKNOWN npm ERR! syscall rename npm ERR! path C:\Users\pratish.devangan\OneDrive - HCL Technologies Ltd&bso ...

What could be causing my Rest API request to malfunction?

Currently, I am working on a Pokedex website as part of my practice to enhance my skills in using API Rest. However, I have encountered some issues with the functionality. When users first enter the site, the API is being called twice unnecessarily. Additi ...

Error: The variable "weather" is not defined while using React with the weatherbit API

I'm currently developing a React application that utilizes the Weatherbit API. However, I have encountered an issue with the weather object when calling my data array. Below is the code snippet where the problem occurs: import React from "react&q ...

Enhancing the type safety of TypeScript Generics

Uncertainty looms over me - am I committing an error, or is this all part of the plan... Within my academic domain class Collection<E> { ... } Lies a function public Insert(item: E): void { ... } I construct a specific instance of my list const ...

Using Webdriver to dynamically enable or disable JavaScript popups in Firefox profiles

I am currently working on a test case that involves closing a JavaScript popup. The code functions correctly in a Windows environment, but when I try to deploy it on a CentOS based server, I encounter the following error: Element is not clickable at point ...

Using setInterval in JavaScript to automatically update a TextField

As someone who is relatively new to Javascript and jQuery, I am trying to make a simple code that updates a text field with random values every 5 seconds. However, my implementation does not seem to be working. I apologize if this question seems too basic ...

What strategies can be used to ensure that the page layout adjusts seamlessly to even the smallest shifts in window size?

Of course, I am familiar with media queries and how they allow us to set specific min-width and max-width ranges for CSS changes. However, when I look at the website styledotme.com, I notice that the block/div beneath the navigation bar gradually shrinks ...

Switching from HttpModule to HttpClientModule

Angular's transition from HttpModule to HttpClientModule is causing some confusion, as discussed in detail here. The official Angular tutorial at https://angular.io/tutorial/toh-pt6 still uses HttpModule, while the Fundamentals documentation at https ...

Creating a new music application and looking for ways to keep track of and update the number of plays for

I'm currently developing a music app and am looking for a way to update the play count every time a user listens to a song for at least 30 seconds. I've attempted the following approach: let current_final; let current_initial; ...

Developing a Library for Managing APIs in TypeScript

I'm currently struggling to figure out how to code this API wrapper library. I want to create a wrapper API library for a client that allows them to easily instantiate the lib with a basePath and access namespaced objects/classes with methods that cal ...

Flashing white screen when transitioning between pages on phonegap iOS system

I'm currently using phonegap for my iOS application project. Interestingly, I've noticed a slight white flicker/flash when navigating between pages in the app. To address this issue, I have refrained from using jquery mobile and instead relied ...

Fixing permission issues during the installation of Angular Client on MacOS: A comprehensive guide

As a beginner coder diving into Angular and Node through an Udemy tutorial, I've encountered some issues. While I have successfully installed Node.js version 16.15.1, my attempts to install the angular client have consistently failed (see screenshot a ...

Tips on eliminating the 'first', 'previous', 'next', and 'last' buttons in the twbs pagination plugin

I am searching for a straightforward pagination solution that only displays page numbers without control buttons like "first," "previous," "next," and "last." I have looked through the options available in twbs-pagination's github documentation and on ...

Trouble arises when attempting to showcase document fields in MongoDB

As a beginner in programming, I am putting in my best effort to figure things out on my own. However, I seem to be stuck without any guidance. I am attempting to display all products from the mongoDB based on their brand. While I have successfully set up a ...