Search code examples
vue.jsvuejs2vuexvuetify.js

How to use Vue v-model binding in Vuetify components together with computed properties and Vuex?


I'm trying to use v-radio-group in conjunction with computed values from Vuex as described similarly here.

Example codepen of the issue I'm facing is here

Whenever a radio button is clicked, a Vuex mutation is called to save the selected value in the state.
However it can be the case that some validation fails inside the mutation and that therefore the value is not changed in the state as expected.

Regardless of what value ends up in the Vuex state, the radio buttons do not truly reflect the current state.

E.g. in the codepen snippet I'd expect the second option (Option 1) never to show as chosen, as the corresponding state is always 0.

As far as I can see this behavior is not only happening when using v-radio-groups.
It happens with all Vuetify components using v-model and computed getters/setters.
So e.g. Vuetifys v-text-input/v-text-field and v-select also show the same behavior.

To sum it up, my questions are the following:
Why is the second option in my codepen example getting selected even as the corresponding state is different?
How can I achieve the expected result (Having Option 1 never shown as selected, even when it is clicked)?


Solution

  • As far as I know Vuetify keeps its own state in their components like v-radio-group.

    To change it you need to send updated props. Then it will react and update its own state.

    The trouble is that you are performing validation in a mutation. Which is a bad practice in my opinion.

    I will show you how to "block" changing state and update v-radio-group so its own state corresponds to what is actually in your $store.state.radioState.

    And I will spend some more time to figure out how to performe it in on mutation ;-)

    This is not a perfect solution >> my codepen

    1. Your mutation just updates the state.
    // store.js
    mutations: {
      setRadioState (state, data) {
        state.radioState = data;
      },
    },
    
    
    1. Your set method do the validation.
    // component 
    computed: {
      chosenOption: {
        get () { 
          return this.$store.state.radioState;
        },
        set (value) {
          if (value !== 1) {
           this.$store.commit('setRadioState', value) 
          } else {
            const oldValue = this.$store.state.radioState
            this.$store.commit('setRadioState', value)
            this.$nextTick(() => {
             this.$store.commit('setRadioState', oldValue)
            })
          }
        }
      }
    }
    
    1. What happens in the set when it fails validation? You save current state to oldValue, you update state so it corresponds to v-radio-group component. And in the $nextTick you change it right back to oldValue. That way v-radio-group gets updated props and change its state to yours.