Search code examples
datevue.jscomputed-properties

How to create Date(now) within Vue.js to use in a computed property?


I have an array of calendar events with a pre-formatted date: 20190517T010000Z.

I need to filter the array based upon the following:

1) Future Events (any events occurring greater than NOW)

2) Past Events (any events that occurred less than NOW)

3) New Events created within the past 7 days (NOW - 7 days)

I have an example hardcoded below - but need NOW to be dynamic and based upon the user's system time. I can't figure out how to get NOW in the same format as the datetime format I'm getting in the my array. Also, I don't know where in my code it should reside (within a separate JS file or within the Vue component)?

Once I have it working within the component listed below, it will be moved to a VUEX Getter.

<template>
    <div class="text-left m-4 p-4">
        <div>
            Total Number Events: {{ allEvents.length }}
        </div>
        <div>
            Events Created In Last 7 Days: {{ createdEvents }}
        </div>
        <div>
            Future Events: {{ futureEvents }}
        </div>
        <div>
            Past Events: {{ pastEvents }}
        </div>
    </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState(['allEvents']),

    futureEvents () {
      return this.$store.state.allEvents.filter(allEvents => allEvents.dtstart >= '20190517T010000Z').length
    },

    pastEvents () {
      return this.$store.state.allEvents.filter(allEvents => allEvents.dtstart <= '20190517T235900Z').length
    },

    createdEvents () {
      return this.$store.state.allEvents.filter(
        allEvents => allEvents.created >= '20190511T235900Z' && allEvents.created <= '20190517T235900Z' )
        .length
    }
  },
}
</script>

The above code works - but it is hardcoded right now and it needs to be dynamic. Any thoughts or suggestions would be welcome.


Solution

  • All your date time objects should be persisted as UNIX timestamps (UTC seconds since 1/1/1970). This will allow you to compare times across systems no matter the timezone.

    Provided that the events in your Vuex store are stored with dstart being a UNIX timestamp, the following snippet should give you the dynamic behaviour you want.

    I've created a now attribute in the component's data. This gets updated every second, causing the computed properties to refresh.

    Additionally, if the allEvents property in the Vuex store updates, the computed properties will also refresh.

    <template>
        <div class="text-left m-4 p-4">
            <div>
                Total Number Events: {{ allEvents.length }}
            </div>
            <div>
                Events Created In Last 7 Days: {{ createdEvents }}
            </div>
            <div>
                Future Events: {{ futureEvents }}
            </div>
            <div>
                Past Events: {{ pastEvents }}
            </div>
        </div>
    </template>
    
    <script>
        import { mapState } from 'vuex'
        export default {
            data () {
                return {
                    now: new Date().getUTCSeconds()
                }
            },
            created () {
                this.scheduleUpdateNow();
            },
            methods: {
                updateNow() {
                    this.now = new Date().getUTCSeconds();
                    this.scheduleUpdateNow();
                },
                scheduleUpdateNow() {
                    setTimeout(this.updateNow, 1000);
                }
            },
            computed: {
                ...mapState(['allEvents']),
    
                futureEvents () {
                    return this.$store.state.allEvents.filter(allEvents => allEvents.dtstart > this.now).length
                },
    
                pastEvents () {
                    return this.$store.state.allEvents.filter(allEvents => allEvents.dtstart <= this.now).length
                },
    
                createdEvents () {
                    return this.$store.state.allEvents.filter(
                        allEvents => allEvents.created >= this.now && allEvents.created <= this.now).length
                }
            }
        }
    </script>