I have implemented a 4-digit pin field with a specific behavior: when a field is filled, the focus automatically shifts to the next field (the cursor moves to the next input field). If text in a field is deleted, the text in that field is also removed and the cursor moves back to the previous pin field.
However, there seems to be an issue where sometimes, if a field with text is highlighted and overwritten by typing another key (e.g., to correct a mistake), the input
event is not triggered, causing the cursor to remain in the same field instead of moving to the next one. This inconsistency can lead to a poor user experience, and I need to find a way to ensure that the cursor always switches pin fields when highlighted text is overwritten.
Below are the relevant parts of the code:
data() {
return {
focusIndex: 1,
inputOne: '',
inputTwo: '',
inputThree: '',
inputFour: '',
numberOfPinFields: 4,
};
},
mounted() {
// this highlights the first pin field
this.$refs[this.focusIndex].focus();
},
methods: {
handlePinFieldDeletion() {
if (this.focusIndex > 1) {
this.focusIndex -= 1;
}
},
handlePinFieldInput(value, maxNumberOfFields) {
this.$nextTick(() => {
// after the focus index from the input field watch below is updated, increase the focusIndex value
if (value.length === 1 && this.focusIndex < maxNumberOfFields) {
this.focusIndex += 1;
}
});
},
ensurePinFieldHasOneInput(value) {
return value.slice(0, 1);
},
highlightOnFocus(e, focusIndex) {
// highlight the text
e.target.select();
// set the new focus index
this.focusIndex = focusIndex;
},
}
watch: {
focusIndex(newValue) {
this.$refs[newValue].focus();
},
inputOne(newValue) {
// set focus index of first otp input field to 1 when it changes.
// This will help with situations where the user doesn't use the input fields in numerical order
this.focusIndex = 1;
this.inputOne = this.ensurePinFieldHasOneInput(newValue);
},
inputTwo(newValue) {
// set focus index of first otp input field to 2 when it changes.
// This will help with situations where the user doesn't use the input fields in numerical order
this.focusIndex = 2;
this.inputTwo = this.ensurePinFieldHasOneInput(newValue);
},
inputThree(newValue) {
// set focus index of first otp input field to 3 when it changes.
// This will help with situations where the user doesn't use the input fields in numerical order
this.focusIndex = 3;
this.inputThree = this.ensurePinFieldHasOneInput(newValue);
},
inputFour(newValue) {
// set focus index of first otp input field to 4 when it changes.
// This will help with situations where the user doesn't use the input fields in numerical order
this.focusIndex = 4;
this.inputFour = this.ensurePinFieldHasOneInput(newValue);
},
}
<form>
...
<q-input
type="password"
input-class="text-center"
maxlength="1"
@keyup.delete="handlePinFieldDeletion"
@input="handlePinFieldInput($event, numberOfPinFields)"
v-number-only
@focus="highlightOnFocus($event, 1)"
borderless
ref="1"
v-model="inputOne"
/>
<q-input
type="password"
input-class="text-center"
maxlength="1"
v-number-only
@focus="highlightOnFocus($event, 2)"
@keyup.delete="handlePinFieldDeletion"
@input="handlePinFieldInput($event, numberOfPinFields)"
borderless
ref="2"
v-model="inputTwo"
/>
<q-input
type="password"
input-class="text-center"
maxlength="1"
v-number-only
@focus="highlightOnFocus($event, 3)"
@keyup.delete="handlePinFieldDeletion"
@input="handlePinFieldInput($event, numberOfPinFields)"
borderless
ref="3"
v-model="inputThree"
/>
<q-input
type="password"
input-class="text-center"
v-number-only
@focus="highlightOnFocus($event, 4)"
maxlength="1"
@keyup.delete="handlePinFieldDeletion"
@input="handlePinFieldInput($event, numberOfPinFields)"
borderless
ref="4"
v-model="inputFour"
/>
...
</form>