Ryan H
Ryan H

Reputation: 2945

Update existing object in array vuex

I'm using the latest version of Nuxt JS 2.8.1 to build a hybrid app. I'm utilising the modules mode of Vuex as it's recommended to do this in order for me to save data and access it across different pages, components and layouts.

On one particular page, a settings page that I've built I have a Vuetify switch, essentially a toggle which will push a value of either true or false, I'm using this to implement a dark mode feature and conditionally render styling on the page.

My toggle switch will parse a list of settings which get updated via the v-model on the input and then committed to my store:

HTML

<v-list-tile avatar>
        <v-list-tile-action>
          <v-switch color="primary" v-model="settings.darkMode" @change="saveSetting('darkMode')"></v-switch>
        </v-list-tile-action>
        <v-list-tile-content>
          <v-list-tile-title>Dark mode</v-list-tile-title>
          <v-list-tile-sub-title>Toggle app's dark mode.</v-list-tile-sub-title>
        </v-list-tile-content>
      </v-list-tile>

My JS

data () {
    return {
      settings: {
        darkMode: false,
        dataSaver: false,
      },
      retrieveSettings: null,
      isClearing: {
        local: false,
        sessions: false,
        all: false
      }
    }
  },
methods: {

  /**
     * Save settings to storage
     */
    saveSetting() {
      localStorage.setItem('my_settings',JSON.stringify(this.settings));
      var beacon_settings = JSON.parse(localStorage.getItem('my_settings'));
      this.retrieveSettings = beacon_settings
      this.$store.commit('settings/add', {
        darkMode: this.settings.darkMode,
        dataSaver: this.settings.dataSaver
      })
    }

}

My store/settings.js file (Vuex)

export const state = () => ({
  settings: []
})

export const mutations = {
  add (state, settingsObject) {
    state.settings.push(settingsObject)
  }
}

This will successfully push the data that I can retrieve via a computed property in other pages of my website, however, every time I toggle the switch, it will push a new object into the settings array rather than update the existing one, e.g:

[
  {
    darkMode: true,
    dataSaver: false
  },
  {
    darkMode: false,
    dataSaver: false
  }
]

Preferably I'd like to just update the existing object that was pushed, rather than push another one, I'm struggling with this bit and can't seem to figure this out. I might need to do something with $set but not too sure.

Upvotes: 0

Views: 2824

Answers (2)

Waqas Idrees
Waqas Idrees

Reputation: 1461

The easy way to this you can use the vuex-map-fields npm package. As you are using the list of items you have to use mapMultiRowFields. What you have to do simply generate the automated computed property & on update It will automatically set/update the value in store as well. Your code will be like

HTML:-

<v-list-tile avatar>
        <v-list-tile-action>
          <v-switch color="primary" v-model="settings.darkMode" @change="saveSetting('darkMode')"></v-switch>
        </v-list-tile-action>
        <v-list-tile-content>
          <v-list-tile-title>Dark mode</v-list-tile-title>
          <v-list-tile-sub-title>Toggle app's dark mode.</v-list-tile-sub-title>
        </v-list-tile-content>
      </v-list-tile>

Js:-

import { mapMultiRowFields } from 'vuex-map-fields';
export default {
    data () {
        return {
          retrieveSettings: null,
          isClearing: {
            local: false,
            sessions: false,
            all: false
          }
        }
      },
      computed: {
       ...mapMultiRowFields(['settings']),
    },
    methods: {

      /**
         * Save settings to storage
         */
        saveSetting() {
          localStorage.setItem('my_settings',JSON.stringify(this.settings));
          var beacon_settings = JSON.parse(localStorage.getItem('my_settings'));
          this.retrieveSettings = beacon_settings
        }

    }
}

Upvotes: 0

Alexander Summer
Alexander Summer

Reputation: 11

The outcome is exactly what should be expected using:

state.settings.push(settingsObject)

I would recommend to go along with what was already commented and use an object instead of an array.

Use: settings: {} insted of settings: [] to declare an object and change state.settings.push(settingsObject) to state.settings = settingsObject to override the existing object instead of adding a new object to an array.

See: https://vuex.vuejs.org/guide/mutations.html#mutations-follow-vue-s-reactivity-rules for more information and explanation.

Upvotes: 1

Related Questions