Home > Blockchain >  Vuex returns default values, not provided [Nuxt.js/Vuex]
Vuex returns default values, not provided [Nuxt.js/Vuex]

Time:02-17

I have this simple registration page:

<template>
  <div >

    <div >
      <h1 @click="redirect('/')">Logo</h1>
    </div>

    <div >
      <p >Already have account?
        <span  @click="redirect('/login')">Log in!</span>
      </p>
    </div>

    <div >
      <div >
        <h1>Sign up</h1>
        <Input :error="error" :title="'Email'" :type="'email'" :value="email" />
        <Input :error="error" :title="'Password'" :type="'password'" :value="password" />
        <Input :error="error" :title="'Repeat password'" :type="'password'" :styles="'padding-bottom: 10px'" :value="passwordRepeat" />
        <Checkbox :value="tac" :label="`I have read and accepted <a href='/'>terms and conditions.</a>`" />
        <Button :label="'Sign up'" :clickon="register" />
        <p v-if="error">Passwords have to match!</p>
      </div>
    </div>

  </div>
</template>

<script>
import { register } from "~/api";
import { mapGetters, mapState, mapActions, mapMutations } from 'vuex';
import Input from "~/components/Input";
import Button from "~/components/Button";
import Checkbox from "~/components/Checkbox";
export default {
  name: "register",
  components: {
    Input,
    Button,
    Checkbox
  },
  watch: {
    password() { this.error = (this.password !== this.passwordRepeat) && (this.password !== null && this.passwordRepeat !== null) },
    passwordRepeat() { this.error = (this.password !== this.passwordRepeat) && (this.password !== null && this.passwordRepeat !== null) }
  },
  computed: {
    ...mapGetters({
      email: 'register/getEmail',
      password: 'register/getPassword',
      passwordRepeat: 'register/getPasswordRepeat',
      status: 'register/getStatus',
      error: 'register/getError',
      tac: 'register/getTac'
    })
  },
  methods: {
    redirect(path) {
      this.$router.push({ path })
    },
    async register() {
      console.log(this.tac, this.password, this.passwordRepeat, this.email)
    }
  }
}
</script>

<style lang="scss">
@import "../assets/css/login";
</style>

As you can see, there are 4 fields where I want to change value - 3 Input and 1 Checkbox. When I provide data and click button in console I get the default values, I was trying to do something with mutations and actions, but it doesn't work.

Can it be because I use my components, not default?

Also, here is my store store/register.js

export const state = () => ({
  email: null,
  password: null,
  passwordRepeat: null,
  status: null,
  error: false,
  tac: false
})

export const mutations = {
  setEmail(state, value) { state.email = value },
  setPassword(state, value) { state.password = value },
  setPasswordRepeat(state, value) { state.passwordRepeat = value },
  setStatus(state, value) { state.status = value },
  setError(state, value) { state.error = value },
  setTac(state, value) { state.tac = value }
}

export const actions = {
  fetchEmail(ctx, value) { ctx.commit('setEmail', value) },
  fetchPassword(ctx, value) { ctx.commit('setPassword', value) },
  fetchPasswordRepeat(ctx, value) { ctx.commit('setPasswordRepeat', value) },
  fetchStatus(ctx, value) { ctx.commit('setStatus', value) },
  fetchError(ctx, value) { ctx.commit('setError', value) },
  fetchTac(ctx, value) { ctx.commit('setTac', value) },
}

export const getters = {
  getEmail(state) { return state.email },
  getPassword(state) { return state.password },
  getPasswordRepeat(state) { return state.passwordRepeat },
  getStatus(state) { return state.status },
  getError(state) { return state.error },
  getTac(state) { return state.tac },
}

If problem is that I use not default tags, but my components with props, here is Checkbox component:

<template>
  <div >
    <label >
      <input type="checkbox" :value="innerValue" @input="onInput">
      <span ></span>
    </label>
    <p  v-html="label" />
  </div>
</template>

<script>
export default {
  props: {
    label: {
      type: String,
      default: ''
    },
    value: {
      type: Boolean,
      default: false
    }
  },
  name: "Checkbox",
  watch: {
    value(value) {
      this.innerValue = value
    },
    innerValue(value) {
      this.$emit('input', value)
    }
  },
  data() {
    return {
      innerValue: this.value
    }
  },
  methods: {
    onInput() {
      this.$nextTick(() => {
        this.innerValue = !this.innerValue
      })
    }
  }
}
</script>

CodePudding user response:

One way that can help you change the value of your checkbox is like this.

Checkbox Component:

<template>
  <div >
    <label >
      <input type="checkbox" @change="$emit('checkbox', value)" />
      <span ></span>
    </label>
  </div>
</template>

<script>
export default {
  name: 'Checkbox',
  data() {
    return {
      value: false,
    }
  },
}
</script>

Now inside your register page you can use the checkbox component in template like this:

<Checkbox @checkbox="checkboxChanged" />

Now in the same page and in method section add this method:

checkboxChanged(event) {
      this.$store.dispatch('register/fetchTac', event)
    },
},

This way, when the value of checkbox changes you can have the changed value in your store too and get it with mapGetter. You can do the same to your inputs.

CodePudding user response:

Okay, here is my working answer, I don't really know if it's correct, but it doesn't contain any errors or warnings:

<template>
  <div >

    <div >
      <h1 @click="redirect('/')">Logo</h1>
    </div>

    <div >
      <p >Already have account?
        <span  @click="redirect('/login')">Log in!</span>
      </p>
    </div>

    <div >
      <div >
        <h1>Sign up</h1>
        <Input :error="error" :title="'Email'" :type="'email'" v-model="email" />
        <Input :error="error" :title="'Password'" :type="'password'" v-model="password" />
        <Input :error="error" :title="'Repeat password'" :type="'password'" :styles="'padding-bottom: 10px'" v-model="passwordRepeat" />
        <Checkbox v-model="tac" :label="`I have read and accepted <a href='/'>terms and conditions.</a>`" />
        <Button :label="'Sign up'" :clickon="register" />
        <p v-if="error">Passwords have to match!</p>
      </div>
    </div>

  </div>
</template>

<script>
import { register } from "~/api";
import { mapGetters, mapState, mapActions, mapMutations } from 'vuex';
import Input from "~/components/Input";
import Button from "~/components/Button";
import Checkbox from "~/components/Checkbox";
export default {
  name: "register",
  components: {
    Input,
    Button,
    Checkbox
  },
  watch: {
    ...mapActions(['fetchTac', 'fetchError', 'fetchStatus', 'fetchPasswordRepeat', 'fetchPassword', 'fetchEmail']),
    password() { this.error = (this.password !== this.passwordRepeat) && (this.password !== null && this.passwordRepeat !== null) },
    passwordRepeat() { this.error = (this.password !== this.passwordRepeat) && (this.password !== null && this.passwordRepeat !== null) }
  },
  computed: mapGetters(['getError', 'getEmail', 'getPassword', 'getPasswordRepeat', 'getStatus', 'getTac']),
  data() {
    return {
      email: null,
      password: null,
      passwordRepeat: null,
      status: null,
      error: false,
      tac: false
    }
  },
  methods: {
    redirect(path) {
      this.$router.push({ path })
    },
    async register() {
      console.log(this.passwordRepeat, this.password, this.email, this.tac)
    }
  }
}
</script>

But I still have one problem, as you can see, I have getters and data at the same time, I can actually remove data, but it will cause such warning:

Property or method "propname" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property

It will work, but I will have this warning.

EDIT

I solved this problem that way:

computed: {
    error: {
      get() { return this.$store.getters.getError },
      set(value) { this.$store.commit('setError', value) }
    },
    email: {
      get() { return this.$store.getters.getEmail },
      set(value) { this.$store.commit('setEmail', value) }
    },
    password: {
      get() { return this.$store.getters.getPassword },
      set(value) { this.$store.commit('setPassword', value) }
    },
    passwordRepeat: {
      get() { return this.$store.getters.getPasswordRepeat },
      set(value) { this.$store.commit('setPasswordRepeat', value) }
    },
    status: {
      get() { return this.$store.getters.getStatus },
      set(value) { this.$store.commit('setStatus', value) }
    },
    tac: {
      get() { return this.$store.getters.getError },
      set(value) { this.$store.commit('setTac', value) }
    }
  },
  // data() {
  //   return {
  //     email: null,
  //     password: null,
  //     passwordRepeat: null,
  //     status: null,
  //     error: false,
  //     tac: false
  //   }
  // },
  • Related