I have a multistep form on vue js. I need to dynamically during input send requests, validate on the server and receive a response to display validation errors.
My data:
data() {
return {
form: {...this.candidate}, // we get an object with fields already filled *
errors: new Errors(), // object with validation errors
}
},
Now for each input I have computed property:
characteristicFuturePlans: {
get() {
return this.form.characteristic_future_plans;
},
set(value) {
this.saveField('characteristic_future_plans', value);
}
},
saveField method sends data:
saveField(field, value) {
this.form[field] = value; // keep the data in the object relevant
axios.put(`/api/candidate/${this.candidate.token}`, {[field]: value})
.then(() => { this.errors.clear(field) })
.catch((error) => {
this.errors.record(field, error.response.data.errors[field]);
});
},
Now, with each change of input, a request will be sent. But with this approach, when we quickly type text in a field, sometimes the penultimate request sent comes after the last. It turns out that if you quickly write "Johnny", sometimes a query with the text "Johnn" will come after a query with the text "Johnny" and the wrong value will be saved in the database.
Then I made sure that the data was sent 1 second after the termination of text input. Added timerId: {} to data(){} and then:
saveField(field, value) {
if(this.timerId[field]) {
clearTimeout(this.timerId[field]);
}
this.timerId[field] = setTimeout(this.send, 1000, field, value);
},
send(field, value) {
this.form[field] = value;
axios.put(`/api/candidate/${this.candidate.token}`, {[field]: value})
.then(() => { this.errors.clear(field) })
.catch((error) => {
this.errors.record(field, error.response.data.errors[field]);
});
},
But now, if after filling in the input in less than a second, press the button to go to the next step of the form, the page will simply refresh. (the button to go to the next step will send a request to the server to check if the required fields are filled)
How correctly save data to the database during text input? Can I do this without setTimeout()? If so, how can I make sure that the data of the last request, and not the penultimate, is stored in the database? I will be glad to any tip.
Updated. Attach some template code.
Part of Step[i].vue component:
<div class="row">
<div class="form-group col-md-6">
<element-form title="Title text" :error="errors.get('characteristic_future_plans')" required isBold>
<input-input v-model="characteristicFuturePlans" :is-error="errors.has('characteristic_future_plans')"
:placeholder="'placeholder text'"/>
</element-form>
</div>
</div>
template of input-input component:
<input :value="value" :type="type" class="form-control" :class="isErrorClass"
:placeholder="placeholder" @input="$emit('input',$event.target.value)">
Components of form steps are called from the Page component. Nearby is the component of the button for moving to the next step.
<component :is="currentStep"
:candidate="candidate"
// many props
:global-errors="globalErrors"/>
<next-step :current-step="step" :token="candidate.token"
@switch-step-event="switchStep" @throw-errors="passErrors"></next-step>
NextStep component sends a request to the server, it is checking whether the required fields are filled in the database. If not, throw out a validation error. If so, go to the next form step.