Tips for postponing the first button event in Vue 3 and JavaScript

My current task involves setting up a button event in Vue 3 that triggers a setTimeout countdown on the button before redirecting to another page. The event function has a conditional statement that initiates a countdown from 5 to 0 as long as the countValue is greater than 0. The recursive nature of the setTimeout function ensures that it calls the goHome() function repeatedly to execute the countdown. Once the countValue reaches 0, the router.push method is used to navigate to a different page. However, I am facing an issue where the countdown immediately jumps from 5 to 4 when the button is pressed. I would like to introduce a brief delay at the start of the countdown, so it does not instantly drop to 4. How can I resolve this?

Below is the code snippet I have been working on:

Template:

<div>
  <button @click="goHome" type="button" :disabled="disabledOnCount === true ? true : false">Go Home in {{ countValue }} seconds</button>
</div>

Script:

import { ref } from '@vue/reactivity'

const countValue = ref(5)

const goHome = () => {
  if (countValue.value > 0) {
    disabledOnCount.value = true
    countValue.value -= 1
    setTimeout(() => {
      goHome()
      if (countValue.value === 0) {
        router.push({ name: 'home' })
      }
    }, 1000)
  }
}

Answer №1

Initially, the countdown immediately jumps to 4 because the function goHome() decreases the value instantly and then sets a timeout to check the value. Both actions should occur in the same execution cycle:

const goHome = () => {
  if (countValue.value > 0) {
    disabledOnCount.value = true
    countValue.value -= 1 // ❌ decremented immediately
    setTimeout(() => {
      goHome()
      if (countValue.value === 0) {
        router.push({ name: 'home' })
      }
    }, 1000)
  }
}

Solution

To improve the functionality, a few changes were made:

  1. The goHome() function should always include a call to setTimeout() for consistent delayed effects.

  2. The timer callback now checks only when the countdown is above zero before invoking goHome(). This prevents unnecessary calls when the countdown reaches zero.

const goHome = () => {
  disabledOnCount.value = true

  1️⃣
  setTimeout(() => {
    if (countValue.value > 0) {
      countValue.value -= 1
      if (countValue.value === 0) {
        router.push({ name: 'home' })
      } else {
        2️⃣
        goHome()
      }
    }
  }, 1000)
}

If there is a possibility of the page being unmounted before the timer completes (e.g., user navigates away), it's crucial to stop the timer to prevent unexpected behavior like sudden redirection after navigating away. To achieve this, track the timer ID and use the onUnmounted hook to clear the timeout:

import { onUnmounted } from 'vue'

let countdownTimerId = null

const goHome = () => {
  countdownTimerId = setTimeout(() => {
    /* same as above */

    if (countValue.value === 0) {
      countdownTimerId = null
    }
  }, 1000)
}

onUnmounted(() => clearTimeout(countdownTimerId))

Check out the demo

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

Retrieving date from timestamp in a node.js environment

Can someone help me figure out how to display my timestamp as the date in the front end? I've tried multiple methods without success. Here is the code snippet: formulaire.addEventListener('submit', posteValidation); /** * Function to add a ...

How to disable the underline styling for autocomplete in a React Material UI component

Seeking assistance with removing underline styling and changing text color upon focus within the autocomplete component of React Material UI. Struggling to locate the specific style needing modification. Appreciate any help in advance! ...

Dynamically add index to attribute as it updates

Having an issue with my dynamic button element: <button v-on:click="changeRecord(element)" v-b-modal.modal-5>Aendern</button> This button is generated dynamically within a v-for loop. Instead of manually including the attribute name like v-b- ...

Encountering a roadblock while trying to work with AngularJS Material radio buttons

In one of my projects, I have implemented a polling system where users can choose a question from a list and then proceed to the options page. On the options page, users can select their answer choices and submit their responses. The results are then displ ...

How can I assign integer values to specific child elements after splitting them?

Below is the HTML code that needs modification: <div class="alm-filter alm-filter--meta" id="alm-filter-1" data-key="meta" data-fieldtype="checkbox" data-meta-key="Cate" data-meta-compare="IN" data-meta-type="CHAR"> <ul> <li class=" ...

Js: Automatically populating data into various input fields

I've encountered an issue with form input value injection using a <script> and POST requests. When I attempt to create another form with the same input field (same name and id), the value injection doesn't work, and troubleshooting has bee ...

Using JavaScript to modify the text of a label seems to be a challenging

UPDATE: After carefully reviewing my code once again, I have identified the issue. The problem lies in the positioning of a certain function (unfortunately not included here), but rest assured that I have rectified it! Allow me to provide a brief summary ...

Converting a JSON object into a format suitable for transmission through AJAX requests

I am attempting to transmit data in a JSobject via AJAX using jQuery. Below is the json object: var cookieData = { 'land' : document.URL, 'ref' : document.referrer }; The object is then stored in a cookie... throu ...

Notification within the conditional statement in React JS

I am working on validating phone number input within a React JS component using an if/else statement. If the user enters letters instead of numbers, I want to display a message saying "please check phone number". While I have been able to create a function ...

Tips for displaying placeholder in cropper following an upload

I am currently working with vue-cropper 4.1 using cropperjs in combination with Nuxt 2.13. When my cropper loads, it displays a placeholder image. However, after choosing and uploading a new image, the cropper still shows the previously chosen image instea ...

How can I retrieve information on a logged in Auth0 user from an API?

I'm currently working on a React application that utilizes auth0 in conjunction with an express API server. One issue I'm facing is how to access user information within the API when a secure endpoint is called. While I can retrieve user data on ...

Enhancing the node module of a subpackage within Lerna: A step-by-step guide

I recently integrated lerna into my workflow to streamline the installation of all node modules for multiple sub packages with just one command. Currently, I'm only utilizing the lerna bootstrap feature. Here's a snippet from my lerna.json: { & ...

Correct validation is not achieved when the "!" symbol is used in the matches function

I am working on a React and Next.js project where I am using Formik for handling forms and Yup for validations. One specific input field requires some validations to be performed. This field must be required, so if the user does not enter any information, ...

Explore within another map and analyze the node to spot the differences

I have some questions about iterating through a JavaScript Object and using array functions in JavaScript. Let's assume I have the following variables: var json1 = "[{"id": 1, "name":"x"}, {"id": 2, "name":"y"}]"; var json2 = "[{"id": 1, "name":"x"}, ...

The JSON data structure is not being maintained

I am facing an issue with updating the json object model values using the code below. Even after changing the values, it seems like the model is not getting updated. I tried removing the async code and that worked. Why does the async code not work in this ...

Dynamically loading components within an Angular application

I am tasked with displaying different components at specific times by iterating through them. Below is an example of how I have attempted to achieve this. The components I can use are determined by the server. <ngb-tabset [activeId]="1"> ...

Calculate the sum of multiple user-selected items in an array to display the total (using Angular)

Within my project, specifically in summary.component.ts, I have two arrays that are interdependent: state: State[] city: City[] selection: number[] = number The state.ts class looks like this: id: number name: string And the city.ts class is defined as f ...

Displaying a message text upon successful AJAX request

I have a web page with an AJAX request that updates data in the database. After the update, I want to display a message to the user on the webpage confirming that the data has been successfully updated. However, currently, no message is being displayed and ...

Guide on extracting the ID within a for loop and incorporating it into a Vue.js function

In order to make an API request, I need to retrieve the id. However, whenever I try to include <a v-on:click="showRecipe({{inf.Id}})">Recipe</a> in my code, the entire page crashes. Removing this line resolves the issue. How can I pass the id ...

Utilizing StyleFunctionProps within JavaScript for Chakra UI Enhancements

I need help figuring out how to implement StyleFunctionProps in my Chakra UI theme for my NextJS project. The documentation on Chakra's website provides an example in Typescript, but I am working with Javascript. Can someone guide me on adapting this ...