Search code examples
htmlvue.jsvuexvuejs3

Vue js 3 - Form input values gets cleared after other input changes


I have a form where all input fields are made reactive with an array of values in a Vuex store.

Here is the form :

    <form @submit="submitForm">
    <div class="mb-3">
        <label for="nom" class="form-label">Nom:</label>
        <input :value="nom" @input="onInputChange" type="text" class="form-control" id="nom" placeholder="Nom"
            name="NOM">
        <span style="color: red">{{ fieldErrors.nom }}</span>
    </div>
    <div class="mb-3">
        <label for="prenom" class="form-label">Prénom:</label>
        <input :value="prenom" @input="onInputChange" type="text" class="form-control" id="prenom"
            placeholder="Prénom" name="PRENOM">
        <span style="color: red">{{ fieldErrors.prenom }}</span>
    </div>
    <div class="mb-3 mt-3">
        <label for="email" class="form-label">Courriel:</label>
        <input :value="email" @input="onInputChange" type="text" class="form-control" id="email"
            placeholder="Email" name="EMAIL" />
        <span style="color: red">{{ fieldErrors.email }}</span>
    </div>
    <div class="mb-3 mt-3">
        <label for="phone" class="form-label">Téléphone:</label>
        <input :value="phone" @input="onInputChange" type="text" class="form-control" id="phone"
            placeholder="Numéro de téléphone" name="PHONE" />
        <span style="color: red">{{ fieldErrors.phone }}</span>
    </div>
    <div class="mb-3 mt-3">
        <label for="postalCode" class="form-label">Code postal:</label>
        <input :value="postalCode" @input="onInputChange" type="text" class="form-control" id="postalCode"
            placeholder="Code Postal" name="POSTALCODE" />
        <span style="color: red">{{ fieldErrors.postalCode }}</span>
    </div>
    <div class="mb-3 mt-3">
        <input :checked="termsAndConditions" @change="onInputChange" type="checkbox" class="me-1" id="chkTerms"
            placeholder="TERMS AND CONDITIONS" name="TERMS_AND_CONDITIONS" />
        <label for="chkTerms" class="form-label">I accept the terms and conditions:</label>
        <span style="color: red">{{ fieldErrors.termsAndConditions }}</span>
    </div>
</form>

All inputs share the same function (onInputChange) when there is a change to the value

Here are the computed properties used for the form as well as the function mentionned above:

    computed: {
    ...mapGetters(["nom", "prenom", "email", "phone", "postalCode", "termsAndConditions", "items"]),
},
methods: {
    onInputChange(evt) {
        const element = evt.target;
        const value =
            element.name === "TERMS_AND_CONDITIONS"
                ? element.checked
                : element.value;
        store.commit('UPDATE_'+element.name, value);
    },

As you can see, whenever there is a change in inputs, the appropriate mutation will be called from the store.

Here is the store and all the relevant mutations:

const state = {
    fields: {
        nom: '',
        prenom: '',
        email: '',
        termsAndConditions: false,
        phone:'',
        postalCode:'',
    },
}

    const mutations = {
        UPDATE_NOM(state, payload) {
            state.fields.nom = payload;
        },
        UPDATE_PRENOM(state, payload) {
            state.fields.prenom = payload;
        },
        UPDATE_EMAIL(state, payload) {
            state.fields.email = payload;
        },
        UPDATE_PHONE(state, payload){
            state.fields.phone = payload
        },
        UPDATE_POSTALCODE(state, payload){
            state.fields.postalCode = payload
        },
        UPDATE_TERMS_AND_CONDITIONS(state, payload) {
            state.fields.termsAndConditions = payload;
        },
    }

The problem is: Whenever there is a change in state on the checkbox, the values in the textboxes nom, phone and postalCode are cleared. Their corresponding values in the store stay the same though and the textboxes prenom and email don't have their values cleared at all.

What is this behavior and why is it happenning?

Note: For reproduction sake, I am using bootstrap 5 so you might want to remove the classes if they cause a problem


Solution

  • All your <input> elements bind value to a different store getter, not the actual state. You didn't post what your getters are and the error is likely there, but you say your state remains correct when you toggle the checkbox, so just bind your <input> elements to the actual state, i.e. use mapState instead of mapGetters. Even better, two-way bind your state with v-model on your <input> instead of the combination of :value + @input:

        <div class="mb-3 mt-3">
          <label for="postalCode" class="form-label">Code postal:</label>
          <input
            v-model="$store.state.fields.postalCode"
            type="text"
            class="form-control"
            id="postalCode"
            placeholder="Code Postal"
            name="POSTALCODE"
          />
        </div>
        <span style="color: red">{{ fieldErrors.postalCode }}</span>
        <div class="mb-3 mt-3">
          <input
            v-model="$store.state.fields.termsAndConditions"
            type="checkbox"
            class="me-1"
            id="chkTerms"
            placeholder="TERMS AND CONDITIONS"
            name="TERMS_AND_CONDITIONS"
          />
          <label for="chkTerms" class="form-label"
            >I accept the terms and conditions:</label
          >
          <span style="color: red">{{ fieldErrors.termsAndConditions}}</span>
        </div>
    

    no onInputChange(), mapState, or even mutations needed