Watching array stored in Vuex in VueJS
Asked Answered
C

4

11

I have a customer list which is actually an array of objects. I store it in Vuex. I render the list in my component and each row has a checkbox. More precisely I use keen-ui and the checkbox rendering part looks like:

<tr v-for="customer in customers" :class="{ selected: customer.selected }">
    <td>
      <ui-checkbox :value.sync="customer.selected"></ui-checkbox>
    </td>
    <td>{{ customer.name }}</td>
    <td>{{ customer.email }}</td>
</tr>

So the checkbox directly changes customers array which is bad: I use strict mode in Vuex and it throws me an error.

I want to track when the array is changed and call an action in order to change the vuex state:

watch: {
 'customers': {
  handler() {
    // ...
  },

  deep: true
}

However it still changes the customer directly. How can I fix this?

Charente answered 10/8, 2016 at 13:38 Comment(1)
what about creating a deep copy of the original customer array and use in the template ?Magniloquent
D
2

First and foremost, be careful when using .sync: it will be deprecated in 2.0.

Take a look at this: http://vuex.vuejs.org/en/forms.html, as this problem is solved in here. Basically, this checkbox should trigger a vuex action on input or change. Taken from the docs:

<input :value="message" @input="updateMessage">

Where updateMessage is:

vuex: {
  getters: {
    message: state => state.obj.message
  },
  actions: {
    updateMessage: ({ dispatch }, e) => {
      dispatch('UPDATE_MESSAGE', e.target.value)
    }
  }
}

If you do not wish to track the mutations, you can move the state of this component away from vuex, to be able to use v-model in all its glory.

Daedalus answered 10/8, 2016 at 23:37 Comment(1)
Meant Vue 3.0 ?Neo
R
1

You just have to make a custom getter and setter:

<template>
    <ui-checkbox :value.sync="thisCustomer"></ui-checkbox>
</template>

<script>
    //this is using vuex 2.0 syntax
    export default {
        thisCustomer: {
            get() {
                return this.$store.state.customer;
            },
            set(val) {
                this.$store.commit('SET_CUSTOMER', val);
                // instead of performing the mutation here,
                 // you could also use an action:
                  // this.$store.disptach('updateCustomer')
            }
       },
   }
</script>

In your store:

import {
    SET_CUSTOMER,
} from '../mutation-types';

const state = {
    customer: null,
};

const mutations = {
    [SET_CUSTOMER](state, value) {
        state.customer = value;
    },
}

I'm not exactly sure what your store looks like, but hopefully this gives you the idea :)

Retrogress answered 12/11, 2016 at 0:52 Comment(1)
This answer fails to properly explain how to use a computed property with a v-for, a statement that the op is showing in his codeChaldea
O
1

if your customers are in the root state, you can try this:

watch: {
 '$store.state.customers'{
   handler() {
    // ...
   },

   deep: true
 }
}
Olive answered 1/12, 2021 at 16:54 Comment(0)
I
1

try using mapState in your component and watch the customers like you have done above.worked for me

Islamize answered 19/12, 2022 at 12:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.