MartiNeo
MartiNeo

Reputation: 57

setInterval() in Vue makes my this-variable undefined

Helloo, so I'm making a basic clock in Vue and for some reason with this code I get the initial time value into bazinga, but once it updates it states that it is undefined. I managed to "make it work" if I define now and other variables inside the setInterval() function as well, but this does not seem like a good choice. How come this.bazinga becomes undefined after the first iteration?

<template>
    <div id="clock">
        <h2>The time is now</h2>
        <p>{{ bazinga }}</p>
        
    </div>
</template>

<style>

</style>

<script>
export default {
    data(){
        const now = new Date()
        const hours = now.getHours()
        const minutes = now.getMinutes()
        const seconds = now.getSeconds()
        return{
            bazinga: now
        }
    },
    created() {
         setInterval(() => {
            console.log(this.bazinga)
            this.bazinga = this.now
            console.log(this.bazinga)
        }, 1000)
    },
    destroyed() {
        clearInterval(this.now)
    }
}
</script>

Upvotes: 1

Views: 1150

Answers (2)

Kapcash
Kapcash

Reputation: 6909

All your const variables inside the data property are not registered as component's data, they are just variables accessible in the data block.

I assume you want to get an updated new Date() everytime you call this.now?

I'd suggest something like that:

<script>
export default {
    data(){
        return{
            now: new Date();
        }
    },
    computed {
      hours: function() {
          return this.now.getHours()
      }
      minutes: function() {
          return this.now.getMinutes()
      },
      seconds: function() {
          return this.now.getSeconds()
      }
    },
    created() {
         setInterval(() => {
            this.updateNow()
        }, 1000)
    },
    updateNow() {
       this.now = new Date()
    }
    destroyed() {
        clearInterval(this.now)
    }
}
</script>

Every call to updateNow() will get a new Date, and update all the computed as well. :)

Upvotes: 3

Justin Duncan
Justin Duncan

Reputation: 135

<template>
    <div id="clock">
        The Time is Now {{bazinga}}
    </div>

</template>

<script>
export default {
    data(){
        return {
            hours: 0,
            minutes: 0,
            seconds: 0,
            hoursDisplay: 0,
            secondIterator: 1000,
            hourTime: 12,
        }
    },
    mounted() {
        this.$options.timer = window.setTimeout(this.updateDateTime, this.secondIterator);
    },
    destroyed() {
        window.clearTimeout(this.$options.timer);
    },
    methods: {
        updateDateTime() {
            const now = new Date();
            this.hours = now.getHours();
            this.minutes = this.zeroPad(now.getMinutes());
            this.seconds = this.zeroPad(now.getSeconds());
            this.hoursDisplay = this.hours % this.hourTime || this.hours;
            this.$options.timer = window.setTimeout(this.updateDateTime, this.secondIterator);
        },
        zeroPad: function (time) {
            return (parseInt(time, 10) >= 10 ? '' : '0') + time;
        }
    },
    computed: {
        amPm: function () {
            if (this.hours) {
                return this.hours >= 12 ? 'PM' : 'AM';
            }
        },
        bazinga: function () {
            if (this.amPm) {
                return [this.hoursDisplay, this.minutes, this.seconds].join(':') + ' ' + this.amPm;
            }

        },
    }
}
</script>

I made a clock component here, but basically you always want to use data props inside your components and access them with this.someproperty. You can also use watchers or computed properties to return them manipulated like i have done here.

Upvotes: 1

Related Questions