Search code examples
javascriptvue.jsnativescriptvuexnativescript-vue

Nativescript Vue Timepicker with Vuex


I'm working on a Nativescript-Vue app, and I'm trying to use Vuex to store the hour and minute from a Timepicker to use in other Pages. I've tried catching the event with a computed property, but is there a better way of doing this with Vue?

Here's what I have:

// In NotifyTimePicker.vue (a custom Time-picking modal)
// Template:
<TimePicker row="2" col="0" colSpan="3" horizontalAlignment="center" :hour="selectedFromHour" :minute="selectedFromMinute" />

//Script
computed: {
      selectedFromHour: {
        get: function () {
          return this.$store.state.notifyFromTimeHour
        },
        set: function (newValue) {
          console.log(`Attempting to Update Store with new From Hour = ${newValue}`)
          this.$store.commit('changeNotifyFromTimeHour', newValue)
        }
      },
      selectedFromMinute: {
        get: function () {
          return this.$store.state.notifyFromTimeMinute
        },
        set: function (newValue) {
          console.log(`Attempting to Update Store with new From Minute = ${newValue}`)
          this.$store.commit('changeNotifyFromTimeMinute', newValue)
        }
      },
    },

Then, in my Vuex store:

export default new Vuex.Store({
  state: {
    notifyFromTimeHour: 9,
    notifyFromTimeMinute: 30,
  },
  mutations: {
    changeNotifyFromTimeHour (state, hour) {
      state.notifyFromTimeHour = hour
    },
    changeNotifyFromTimeMinute (state, minute) {
      state.notifyFromTimeMinute = minute
    },
  },
  actions: {

  }
});

It appears that the default values from the Store get pulled into the component just fine, but when changing the time in the picker, the 'set' part of the computed function never fires, and I never see my console.logs firing.

Should I be listening to a different change event? The documentation here doesn't go into detail on this much.

Thanks for the help!


Solution

  • Since all props in Vue are one-way bound, the Timepicker props are only used to set initial values.

    Instead, you can use a v-model binding with a computed getter and setter which reads from / writes to your store

    <TimePicker
      row="2" 
      col="0" 
      colSpan="3"
      horizontalAlignment="center"
      v-model="selectedTime"
    />
    
    export default {
      computed: {
        selectedTime: {
          get () {
            const time = new Date()
            time.setHours(
                this.$store.state.notifyFromTimeHour, 
                this.$store.state.notifyFromTimeMinute)
            return time
          },
          set (time) {
            this.$store.commit('changeNotifyFromTimeHour', time.getHours())
            this.$store.commit('changeNotifyFromTimeMinute', time.getMinutes())    
          }
        }
      }
    }
    

    Alternatively, to listen for updates, you need to use the timeChange event

    <TimePicker
      row="2" 
      col="0" 
      colSpan="3"
      horizontalAlignment="center"
      :hour="selectedFromHour"
      :minute="selectedFromMinute"
      @timeChange="changeTime"
    />
    
    import { mapState } from "vuex"
    
    export default {
      computed: mapState({
        selectedFromHour: "notifyFromTimeHour",
        selectedFromMinute: "notifyFromTimeMinute"
      }),
      methods: {
        changeTime (payload) {
          // documentation doesn't say what the event payload is, let's assume it's a Date
          this.$store.commit('changeNotifyFromTimeHour', payload.getHours())
          this.$store.commit('changeNotifyFromTimeMinute', payload.getMinutes())
        }
      }
    }