Troubleshooting: Dealing with Stack Overflow Error when using setInterval in Vue Programming

I am facing a stack overflow error while creating a timer using Vue, and I'm struggling to understand the root cause. Can someone provide insights on the following code:

Here is my template structure:

<span class="coundown-number">  {{ minutesRemaining }} : {{ secondsRemaining }}</span>
<span v-if="countdownDone"&g DONE </span>
<button v-if="running" class="custom-button" type="button" @click="runCountdown(countdownTime)">Start</button>
<input class="set-time" type="number" v-model="countdownTime" placeholder="Enter a Time in Minutes">

This is the implementation in my JavaScript file:

export default {
  name: 'Countdown',
  props: {
  },
  data() {
    return {
      running: true,
      countdownTime: null,
      remainingTime: null,
      countdownDone: false,
    }
  },
  computed: {
    minutesRemaining() {
      return (this.remainingTime - (this.remainingTime % 60)) / 60;
    },
    secondsRemaining() {
      return this.remainingTime % 60;
    },

  },
  methods: {
    runCountdown(timerTime) {
      let currentTime = timerTime*60;
      this.remainingTime = currentTime;
      if (currentTime > 0){
        currentTime--;
        setInterval(this.runCountdown(this.currentTime), 1000);
      }
      else{
        this.countdownDone = true;
      }   
    }
  }
}

I suspect the issue lies with how I'm calling the setInterval function within the same method it's being created. However, I'm unsure of an alternative approach for initialization.

If it were defined externally as

let tick = setInterval(runCountdown, 1000)
, how can I trigger it onclick? Any guidance on resolving this issue and understanding the underlying concept would be greatly appreciated.

Answer №1

Yes, the issue lies here:

runCountdown(timerTime) {
  let currentTime = timerTime*60;
  this.remainingTime = currentTime;
  if (currentTime > 0){
    currentTime--;
    setInterval(this.runCountdown(this.currentTime), 1000); // This specific line
  }
  else{
    this.countdownDone = true;
  }   
}

You're not passing the function as a callback, instead, you're calling it immediately and indefinitely.

The correct approach is to invoke it within a callback in the setInterval method.

setInterval(() => { this.runCountdown(this.currentTime) }, 1000);

Although setInterval will repeatedly call this function at exponential intervals, you might consider utilizing setTimeout for your needs.

setTimeout(() => { this.runCountdown(this.currentTime) }, 1000);

Answer №2

Although Phiter's response did touch on the main question I posed, it unfortunately falls short due to a critical logic flaw in the code.

Let me address the error in my thought process:

methods: {
    runCountdown(timerTime) {
      let currentTime = timerTime*60;
      this.remainingTime = currentTime;
      if (currentTime > 0){
        currentTime--;
        setInterval(this.runCountdown(this.currentTime), 1000);
      }
      else{
        this.countdownDone = true;
      }   
    }

The problem lies in the fact that runCountdown was initially accepting time in minutes and then converting it to seconds within the function itself.

This resulted in a cycle where each callback to runCountdown from setInterval would mistakenly multiply the time by 60 again, leading to an infinite loop of multiplication and subtraction.

To resolve this issue, I introduced a computed property called countdownInSeconds to properly convert the user's input from minutes to seconds, which is then passed as the parameter to runCountdown.

Here's the revised code snippet:

<template>
  <div class="countdown">
    <h1>How long would you like to study for?</h1>
      <span class="countdown-number">  
        {{ minutesRemaining }} : {{ secondsRemaining }}</span>
        <span v-if="countdownDone">DONE</span>
      <button v-if="running" class="custom-button" type="button" 
            @click="runCountdown(countdownInSeconds)">
         Start
      </button>
    <input class="set-time" type="number" v-model="countdownTime" 
      placeholder="Enter a Time in Minutes"> 
  </div>
</template>

<script>

export default {
  name: 'Countdown',
  props: {
  },
  data() {
    return {
      running: true,
      countdownTime: null,
      remainingTime: null,
      countdownDone: false,
    }
  },
  computed: {
    countdownInSeconds(){
      return this.countdownTime * 60;
    },
    minutesRemaining() {
      return (this.remainingTime - (this.remainingTime % 60)) / 60;
    },
    secondsRemaining() {
      return this.remainingTime % 60;
    },

  },
  methods: {
    runCountdown(timerTime) {
      // assign the remainingTime to the current seconds to allow for allow for computed properties to access this loop
      this.remainingTime = timerTime;
      // if the timer time is still above 0, keep running the loop; will also need to check to see if time has been
      // paused, reset or changed
      if (timerTime > 0){
        timerTime--;
        setTimeout(() => {this.runCountdown(timerTime)}, 1000);
      }
      else{
        this.countdownDone = true;
      }   
    }
  }
}
</script>

I hope this explanation clarifies the issue at hand!

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

Distinctive titles for JavaScript constructors/prototypes compared to classes

When working with JavaScript ES6, classes allow us to write code like this: class RectangularShape { constructor(height, width) { this.height = height; this.width = width; } getArea() { return this.height * this.width } static some ...

switching back and forth between the registration and login forms

<script> $(document).ready(function(){ $("#register_link").click(function() { $("#login_or_register").empty(); $("#login_or_register").load("register_form.php"); }); $("#login_link").click(function() { $("# ...

Is it possible to implement localStorage for auto-filling multiple forms simultaneously on a single webpage

I have been exploring a code snippet by Ke Yang that uses localStorage to synchronize text in form fields across different fields. I am interested in implementing something similar. On a page where I have a library of downloadable items, there are approxi ...

Leveraging the Meteor Framework for Application Monitoring

Exploring the potential of utilizing Meteor Framework in a Monitoring Application. Scenario: A Java Application operating within a cluster produces data, which is then visualized by a Web Application (charts, etc.) Currently, this process involves using ...

Struggling to align images side by side using HTML and CSS along with figcaption and buttons

Adding buttons below images on my webpage is proving to be a bit challenging. I tried using the figcaption tag, but it resulted in the images stacking on top of each other instead of side by side. **My HTML:** <section class="mostpurch"> ...

Unable to access an element using jquery

This is an example of an HTML file: <div id ="main"> </div> Here is the JavaScript code: //creating a new div element var divElem = $('<div class="divText"></div>'); //creating an input element inside the div var i ...

Creating a responsive design for mobile apps in Ionic using CSS

I need help with making my Ionic app responsive across all mobile devices. The design on the page was created using CSS, but it is not displaying properly on every device. How can I ensure that it adapts to different screen sizes? <template> <Io ...

Configure the input to accept integer values

This page that I have developed is designed for entering Latitude and Longitude values. <div class="container "> <form class="entry"> <div class="aligncenter"> <h5 style="color:MediumTurquoise; font ...

"Adjusting Material UI Select Size - A Guide to Resizing Your

Struggling with getting Material UI selects to work properly with height and width using 'vh' and 'vw', as well as adjusting text size with 'vh'. The boxes have the correct size, but the label text is no longer centered due t ...

Difficulty encountered when utilizing an if statement within a function

I have encountered a simple issue while using an if statement within a function. The following code is working as intended: <!DOCTYPE html> <html> <body> <h1>Typewriter</h1> <button onclick="typeWriter()">Click me& ...

Learn about generating PDF files with React Native Expo using the react-native-html-to-pdf library!

I'm currently attempting to execute a 'Hello World' code utilizing the react-native-html-to-pdf library in order to generate a PDF, but I am encountering difficulties setting it up in Expo. Would you be able to provide assistance? I have tri ...

Is it possible to resend an AJAX request using a hyperlink?

Is it possible to refresh only the AJAX request and update the content fetched from an external site in the code provided below? $(document).ready(function () { var mySearch = $('input#id_search').quicksearch('#content table', ...

Steps for loading a different local JavaScript file by clicking on a button

My goal is to reload the browser page and display a different ReactJS component/file when a button is pressed. Initially, I attempted using href="./code.js" or window.location="./code.js" within the button props, but unfortunately, it did not yield the des ...

Sleek carousel design with optimal spacing between images

Solving the Issue Utilizing Ken Wheeler's Slick plugin has allowed me to create a carousel on my website. However, I've encountered an issue where the images inside the <a> tag aren't evenly spaced and are even overlapping in some ins ...

The PHP table fails to show up on the screen

I've implemented a PHP script that connects to a MySQL database and is supposed to generate an HTML table. To achieve real-time updates, I've set up a long-polling AJAX script that polls the PHP script every second. Although everything seems to b ...

Utilizing Javascript and CSS for horizontal alignment from left to right

I have a JavaScript function that generates a list of store locations and creates a DIV beneath the map. Currently, the items are displayed top to bottom on the page. However, I would like to change the layout so that the items are shown as 3 in a row fro ...

Reboot JavaScript once a day for optimal performance

Is it possible for the JavaScript's ?random to be based on the current date so that it only loads once a day? <script type="text/javascript" src="http://external.example.com/bookmarklet.js?random"></script> I am asking this question beca ...

Using jQuery to append content with a variable as the source

Recently delving into jQuery and encountering an issue with getting my variable inside src when using append. Either it's not functional at all, or just displaying the variable name in string form in the console. Here is the code causing trouble: va ...

Tips to prevent redundancy in a one-line 'if' statement in JavaScript

While working on a piece of code, I came across something bothersome and couldn't find a solution even after doing some research. It's functional, but it feels redundant to have to type this.className three times: this.className != 'selecte ...

What is the mechanism behind the setTimeout function as an asynchronous timer when we specify a specific duration?

Can you identify the coding instructor, possibly Net Ninja or Fireship, who explained that in asynchronous setTimeout, it promises to run after a minimum time of 1 second but may actually take longer (e.g. 1015 milliseconds or 1200 milliseconds)? What ha ...