2 way data binding with Vuex

Viewed 9083

In the code below I'm 2 way binding the output of a textarea into a p element, once from the component's internal state and once from Vuex. The Vuex state does show the initial value, but the value doesn't update as I add or delete text (as it does correctly with the 1st textarea bound to the internal data). What is the difference that is causing this issue?

Component code:

<template>
  <div>
    <div>
      <textarea name="textarea1" id="txtid" cols="40" rows="30" v-model="internal_state"></textarea>
      <p> {{ internal_state }}</p>
      <hr>

      <textarea name="textarea1" id="txtid" cols="40" rows="30" v-model="this.$store.state.vuex_state"></textarea>
      <p> {{ this.$store.state.vuex_state }}</p>
      <hr>

    </div>
  </div>
</template>

<script>

  export default {
    name: 'WriteArea',
    data () {
      return {
        internal_state: ''
      }
    },
    methods: {


    }
  }

</script>

Vuex code:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const store = new Vuex.Store({
  strict: true,
  state: {
    counter: 0,
    vuex_state: 'starting string'
  },
  getters: {
    vuex_getter1: (state) => {
      return state.vuex_string
    }
  }
})
3 Answers

You can try to use mine library for 2 way binding vuex problem solution

https://github.com/yarsky-tgz/vuex-dot

Example:

<template>
  <input v-model="name"/>
  <input v-model="email"/>
  <button @click.stop="step++">next</button>
</template>

<script>
  import { takeState } from 'vuex-dot';

  export default {
    computed: {
      step: takeState('wizard.step') 
        .commit('setWizardStep')
        .map(),
      ...takeState('user')
        .expose(['name', 'email'])
        .commit('editUser')
        .map()
    }
  }
</script>

store/index.js

export default new Vuex.Store({
  state: {
    wizard: {
      step: 1
    },
    user: {
      name: 'John',
      email: 'john@doe.com'
    }
  },
  mutations: {
    setWizardStep(state, step) {
      state.wizard.step = step;
    },
    editUser(state, patch) {
      state.user = Object.assign({}, state.user, patch);
    }
  }
});

Using: vuex-map-fields

from vuex-map-fields repo:

Enable two-way data binding for form fields saved in a Vuex store.

Vuex Store

import Vue from 'vue'
import Vuex from 'vuex'
import { getField, updateField } from 'vuex-map-fields';

Vue.use(Vuex)

export const store = new Vuex.Store({
  strict: true,
  state: {
    counter: 0,
    vuex_state: 'starting string'
  },
  getters: {
    getField, //  Add the `getField` getter to the `getters` of your Vuex store.
    vuex_getter1: (state) => {
      return state.vuex_string
    }
  }

  mutations: {
    updateField,  // Add the `getField` getter to the `getters` of your Vuex store.
  }
})

Component code:

<template>
  <div>
    <div>
      <textarea name="textarea1" id="txtid" cols="40" rows="30" v-model="internal_state"></textarea>
      <p> {{ internal_state }}</p>
      <hr>

      <textarea name="textarea1" id="txtid" cols="40" rows="30" v-model="vuex_state"></textarea>
      <p> {{ vuex_state }}</p>
      <hr>

    </div>
  </div>
</template>

<script>
import { mapFields } from 'vuex-map-fields';

export default {
  name: 'WriteArea',
  data () {
    return {
      internal_state: ''
    }
  }, 
  computed: {
    // The `mapFields` function takes an array of
    // field names and generates corresponding
    // computed properties with getter and setter
    // functions for accessing the Vuex store.
    ...mapFields([
      'vuex_state ',
    ]),
  },
}

</script>
Related