0

In my nuxtjs app static folder I have a file called data.json

in my component I use this data like so

<script>
import data from '~/static/data.json';
export default {
    data ({ params }) {
        return {
            data
        }
    }
}
</script>

now I have a method that will basically take values from that data and create a little counting up animation like so

methods: {
    countUp(value) {
        for (let i = 0; i <= value; i++) {
            setTimeout(() => {
                return i;
            }, 100);
        }
    }
}

and in my template I am calling it like so

<template>
    <div>
       <p>{{countUp(data.number)}}</p>
    </div>
</template>

now the expected result is for the number to quickly change from 0 to the value but nothing is being printed on the dom if I inspect the html element its empty??

What am I doing wrong??

3
  • What's the timers package? Commented Apr 24, 2019 at 11:10
  • @DecadeMoon it was auto imported via vscode when I wrote setTimeout() I have removed it and the issue still occurs Commented Apr 24, 2019 at 11:12
  • You never return anything from your countUp method, you on;y return from a sub function created in that function Commented Apr 24, 2019 at 11:22

1 Answer 1

1

setTimeout doesn't work the way you think it does:

  • You can't return a value from inside the callback function; nothing is being returned from the countUp method.
  • The call to setTimeout doesn't block, meaning it will return immediately after being called and the callback function passed to it is scheduled for execution asynchronously after the timeout has passed. So every setTimeout call in the for loop will be executed all at once after 100 ms instead of staggered.

You will need to store the current counter value as data on the component so Vue knows to rerender when its value is changed.

The simplest example I can provide follows, but you might want to encapsulate the logic in a separate reusable component.

const value = 50

new Vue({
  el: '#app',

  data: {
    counter: 0,
  },

  methods: {
    countUp() {
      const interval = setInterval(() => {
        this.counter++
        
        if (this.counter >= value) {
          clearInterval(interval)
        }
      }, 100)
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <button @click="countUp">Count Up</button>
  {{ counter }}
</div>

Sign up to request clarification or add additional context in comments.

3 Comments

so my issue with this answer is it doesnt taken in a value and return a value like I want to be able to pass in a number to the method return the number 0 immediately and then have that number change, without having to create a variable for each counter, but i totally understand why the setTimeout wouldnt of worked
It's impossible to do it the way you described; Vue's reactivity system doesn't support it. The counter value needs to be a reactive property on the component so Vue can observe changes to it. If you encapsulate this logic in a separate component then it'll be easier to manage.
@SmokeyDawson also keep in mind that if u are running it in ssr mode than using intervals will leak to memory leaks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.