0

I am trying to set value in to Array in Vuex Store, but caught an error

VueCompilerError: v-model cannot be used on v-for or v-slot scope variables because they are not writable.

Is there any way to realize this? (Without creating local copy of Vuex model array in component)

My component.vue template

<q-input v-for="phone, index  in CompanyPhones" :key="index" v-model="phone" mask="(##) ### ## ##" stack-label label="Phone" />

My component.vue scripts

setup () {
    const $store = useStore()
 const CompanyPhones = computed({
      get: () => $store.getters['CompanySettingsModule/getCompanyPhones'],
      set: (val) => {
        $store.commit('CompanySettingsModule/setCompanyPhones', val)
      }
    })
 return {  CompanyPhones, }
}

Vuex module state.ts

function state (): CompanySettingsInterface {
  return {
    CompanyPhones: ['', '', ''],
  }
}

Vuex module mutations.ts function

setCompanyMails (state: CompanySettingsInterface, val)  { state.CompanyMails = val },

Vuex module getters.ts function

getCompanyPhones (state: CompanySettingsInterface)  { return state.CompanyPhones  },
2
  • could you try binding the v-model to phoneBooks[index]? i know this is supposed to work if the phoneBooks array was just component data, but i'm not quite sure that it would work with computed props as well. worth a try Commented Jun 3, 2021 at 18:28
  • 1
    @Liad I tried, it returns an error [vuex] do not mutate vuex store state outside mutation handlers Commented Jun 3, 2021 at 19:17

1 Answer 1

1

Problem is your computed getter/setter only accepts arrays, and updating a nested value (like companyPhones[index]) will have the same limitations as Vue's standard reactivity. Basically meaning you'll have to replace the array with a clone of itself whenever a child is updated directly. You could do this in a method:

//script
methods: {
  updateCompanyPhone(v, index) {
    const { companyPhones } = this; // destructuring ES6 syntax
    companyPhones[index] = v;
    this.companyPhones = companyPhones;
  }
}

//template
<q-input v-for="phone, index  in CompanyPhones" :key="index" :model-value="phone" @update:model-value="v => updateCompanyPhone(v, index)" mask="(##) ### ## ##" stack-label label="Phone" />

Since v-model is only syntactic sugar you can destructurize it into the :model-value+@update:model-value (Vue3) it represents and have more control over what it does.

If this pattern reoccurs often, you can write a Higher Order Component that maintains an Array with nested values (via value prop and update:value emit, so it works with v-model), with a slot to provide it with a custom form(field) to update its nested values (and maybe some splice/push functions to add/remove items to the array).

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

9 Comments

quasar input does not have :value and @input, thats the problem
According to their own API for the Quasar Input component, it has both the value prop, and emits an input event, both mention being used by v-model. quasar.dev/vue-components/input If yours doesn't work, please share the version of Quasar Framework you're using.
I read the API about value prop => Model of the component; Either use this property (along with a listener for 'input' event) OR use v-model directive, according to this I changed my code <q-input :value="phone" @input="e => UpdateCompanyPhones(e.target.value, index)" stack-label dense class="full-width" color="info" shadow-text="" outlined label="Телефон" > but input does not show anything from store
The version of Quasar Framework "quasar": "^2.0.0-beta.1",
In Quasar v2 the event emitted is named @update:model-value. Read over the fact that you were using Vue 3, they changed v-model since then. (v2 docs here: next.quasar.dev/vue-components/input)
|

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.