6

I'am searching a way to use v-model and :value in same time on the same object.

I got this error:

:value="user.firstName" conflicts with v-model on the same element because the latter already expands to a value binding internally.

The purpose is to set as default value the value get from the mapGetters (coming from one store) and to set the right value when the user will submit the modification. (in onSubmit)

<div class="form-group m-form__group row">
    <label for="example-text-input" class="col-2 col-form-label">
        {{ $t("firstname") }}
    </label>
    <div class="col-7">
        <input class="form-control m-input" type="text" v-model="firstname" :value="user.firstName">
    </div>
</div>


<script>
import { mapGetters, mapActions } from 'vuex';

export default {
    data () {
        return {
            lang: "",
            firstname: ""
        }
    },
    computed: mapGetters([
        'user'
    ]),
    methods: {
        ...mapActions([
            'updateUserProfile'
        ]),
        onChangeLanguage () {
            this.$i18n.locale = lang;
        },
        // Function called when user click on the "Save changes" btn
        onSubmit () {
            console.log('Component(Profile)::onSaveChanges() - called');
            const userData = {
                firstName: this.firstname
            }
            console.log('Component(Profile)::onSaveChanges() - called', userData);
            //this.updateUserProfile(userData);
        },
        // Function called when user click on the "Cancel" btn
        onCancel () {
            console.log('Component(Profile)::onCancel() - called');
            this.$router.go(-1);
        }
    }
}
</script>
Yom T.
  • 8,760
  • 2
  • 32
  • 49
wawanopoulos
  • 9,614
  • 31
  • 111
  • 166

3 Answers3

3

The Vue v-model directive is syntactic sugar over v-bind:value and v-on:input. This alligator.io article helped me a lot to understand how it works.

So basically your problem is that the v-model directive sets value to firstname, while you're also explicitly setting value to user.firstName.

There are a lot of ways to handle this issue. I think a fast and straightforward solution is to store the firstname as a data variable (as you're already doing), and then use only v-model with it, disregarding v-bind:value.

Then, to set the user from the store for the default username, you could set fristname as the store user's username in the created hook:

script:

<script>
import { mapGetters, mapActions } from 'vuex';

export default {
    created() {
      this.firstname = this.user.username; // is this right? no used to the map getters syntax, but this is the idea
    },
    data () {
        return {
            lang: "",
            firstname: ""
        }
    },
    computed: mapGetters([
        'user'
    ]),
    methods: {
        ...mapActions([
            'updateUserProfile'
        ]),
        onChangeLanguage () {
            this.$i18n.locale = lang;
        },
        // Function called when user click on the "Save changes" btn
        onSubmit () {
            console.log('Component(Profile)::onSaveChanges() - called');
            const userData = {
                firstName: this.firstname
            }
            console.log('Component(Profile)::onSaveChanges() - called', userData);
            //this.updateUserProfile(userData);
        },
        // Function called when user click on the "Cancel" btn
        onCancel () {
            console.log('Component(Profile)::onCancel() - called');
            this.$router.go(-1);
        }
    }
}
</script>
Sergeon
  • 6,638
  • 2
  • 23
  • 43
3

Typically you want to set the "initial" value of the v-model on the object itself, like:

data() {
  return {
    firstname: 'someName'
  }
}

But since you're getting it from the store, you could access the specific getter object with this.$store.getters[your_object], so I would remove the :value binding and use v-model alone for this:

<div class="col-7">
  <input class="form-control m-input" type="text" v-model="firstname">
</div>
<script>
export default {
  data() {
    return {
      lang: "",

      firstname: this.$store.getters.user.firstName
    }
  },

  // ...
}
</script>
Yom T.
  • 8,760
  • 2
  • 32
  • 49
  • 1
    Thanks, it works now. I will keep in mind that the best choice is to declare variable in data object whatever the initial value comes from – wawanopoulos Mar 06 '19 at 12:59
  • @wawanopoulos No problem. Even though we could reach out for objects from the store directly, we might really want to limit the "scope" to the current component only, since we're using them as a `v-model` which means they are prone to changes; and with Vuex, we probably can't mutate states without using [`store.commit()`](https://vuex.vuejs.org/api/#commit). – Yom T. Mar 06 '19 at 13:11
1

You should only use v-model, it will create a 2-way binding with the value in your script: changing the variable in js will update the input element, interacting with the input element will update the variable.

If you want to use a default value, just set the variable to that value (wherever it may come from).

Eindbaas
  • 945
  • 1
  • 8
  • 16