5
votes

I am attempting to set and get a username, password, and an authentication boolean from the global vuex state and conditionally render some elements in a navbar. Here is the login component which should pass the data:

<template>
  <div class="login" id="login">
    <b-form-input
      id="inputfield"
      v-model="username"
      type="text"
      placeholder="username">
    </b-form-input>
    <b-form-input
      id="inputfield"
      type="password"
      v-model="password"
      placeholder="password">
    </b-form-input>
    <b-button @click="login()" id = "inputfield" variant="outline-success">
      Login
    </b-button>
  </div>
</template>

<script>
  export default {
    name: 'login',
    computed: {
      username () {
        return this.$store.state.username
      },
      password () {
        return this.$store.state.password
      },
      loggedIn () {
        return this.$store.state.loggedIn
      }
    },
    methods: {
      login () {
        this.$store.dispatch('login', {
          username: this.username,
          password: this.password,
          isAuthed: true // just to test
        })
      }
    }
  }
</script>

However, when i enter anything in the input fields, Vue throws a warning for that field(and the state will not update):

[Vue warn]: Computed property "username" was assigned to but it has no setter.
1

1 Answers

17
votes

You are using v-model with a computed property, so you are actually trying to update that computed property when an input event fires.

Therefore, you need to have setters for your computed properties.

As you are trying to use Vuex state, your setters for your computed properties can commit mutations to the store.

computed: {

  username : {
    get () {
      return this.$store.state.username
    },
    set (value) {
      this.$store.commit('updateUsername', value)
    }
  },

  password : {
    get () {
      return this.$store.state.password
    },
    set (value) {
      this.$store.commit('updatePassword', value)
    }
  },

  ...

},

You will need to have the corresponding mutation for your store, for example:

mutations: {

  updateUsername (state, username) {
    state.username = username
  },

  updatePassword (state, password) {
    state.username = password
  },

  ...

}

For more detail, see the explanation in the Vuex docs here: https://vuex.vuejs.org/en/forms.html




For your login button, you are trying to dispatch an action. If you just want to set a boolean value in the store then you can dispatch the action like this:

methods: {
  login () {
    this.$store.dispatch('login', true)
  }
}

...and then in your store you will need a corresponding action and mutation to commit:

mutations: {
  login (state, value) {
    state.isAuthed = value
  }
},

actions: {
  login ({ commit }) {
    commit('login')
  }
}

Here are the docs for actions: https://vuex.vuejs.org/en/actions.html

I hope this helps.