Reputation: 103
Here is my code. See the <v-text-field>
tag. On keypress
event, it intercepts and transforms the input value into something else if the textbox is full (insert the keypress character at the cursor and push the rest of the characters into the subsequent input boxes).
The input updates with the correct values at first BUT when I blur it (focus out), it goes back to the value that it had before the keypress
event. Also, the spillover character gets correctly prepended in the subsequent input box, but its value doesn't stay -- it changes on focus.
I have not written any event handlers that would do these. I have tried removing <v-form>
and the :rules
attribute.
I've also tried tying each <v-text-field>
to a v-model
and assigning the new input value to the model (2-level array) and when I inspect it in Vue Devtools, I notice that it doesn't update the value until I do the blur/focus. The updated values also seem to be wonky.
I've tried triggering change
, even keyup
, after setting the input value, but to no avail.
I've tried the non-JQuery way of setting the input value, no difference.
Tried with or without event.preventDefault()
within the keypress
handler, no difference.
Tried keyup
instead of keypress
just to see the behavior (I need keyup
) but, same problem.
**UPDATE : also tried removing all v-model
s, no difference.
Vuetify version : 1.5.17.
What could be causing this? Please help! I promise I'll pay it forward and help others here when I have answering rights! Every little hint will help a lot!
<v-stepper
v-model="stepperStep"
>
<v-stepper-items>
<v-form autocomplete="off"
ref="form"
v-model="valid"
lazy-validation >
<v-stepper-content
v-for="n in numLines"
:key="`${n}-content`"
:step="n"
>
<div v-show="false" :id="`wordLine_`+(n-1)" :data-numWords="wordLines[n-1].length" class="wordLine" style="display:flex; justify-content:center; margin:0 0 25px;">
<div v-for="(wordSize, key2) in wordLines[n-1]">
<div class="wordBox" style="display:flex; color:#f00;">
<v-text-field required class="wordInput" data-isWordInput="1" :stepperStep="n" :rel="key2" :rules="requiredRule" outline single-line dense height="36" @click:clear="wordInputCleared(n-1, key2)" :size="wordSize" :maxlength="wordSize"></v-text-field>
</div>
</div>
</div>
</v-stepper-content>
</v-form>
</v-stepper-items>
<v-stepper-header v-show="numLines > 1">
<template v-for="n in numLines">
<v-stepper-step
:key="`${n}-step`"
:complete="stepperStep == n"
:step="n"
:editable="true"
>
</v-stepper-step>
</template>
</v-stepper-header>
</v-stepper>
Under mounted()
:
$(document).on('keypress', '.wordInput input[type="text"]', function(event) {
if (event.keyCode == 32) { event.preventDefault(); return; }
if (event.keyCode == 37 || event.keyCode == 39 || event.keyCode == 9 || event.keyCode == 16) return; // arrow keys, tab, shift
let sizeRemaining = $(this).attr('maxlength') - $(this).val().length;
let selectedText = $(this)[0].value.slice($(this)[0].selectionStart, $(this)[0].selectionEnd);
if (selectedText.length > 0) return; // if text is selected, we want this triggered keystroke to replace the selection (default behavior), not auto-advance
let cursorAtLastPosition = ($(this)[0].selectionEnd == $(this).attr('maxlength'));
if (event.keyCode != 8 && event.keyCode != 46) {
if (sizeRemaining == 0) {
event.preventDefault();
let keyVal = event.key;
let lastCharBeforeDisplaced = $(this).val().charAt($(this).val().length-1);
if (cursorAtLastPosition) {
if (parseInt($(this).attr('rel'))+1 == $(this).closest('.wordLine').attr('data-numWords')) { // last wordbox
if (_this.stepperStep == _this.numLines) { // last/only line
$('#btnFinished').focus(); return;
}
} else {
let $nextWord = $(this).closest('.wordLine').find('.wordInput').find('input[type="text"][rel="'+(parseInt($(this).attr('rel'))+1)+'"]');
lastCharBeforeDisplaced = keyVal;
}
} else { // insert keyVal at cursor
let lastCharRemoved = $(this).val().slice(0, -1);
$(this).val(lastCharRemoved.slice(0, $(this)[0].selectionEnd) + keyVal + lastCharRemoved.slice($(this)[0].selectionEnd));
}
_this.cascadeInsertNextWordbox($(this), lastCharBeforeDisplaced);
}
}
});
Under methods
:
cascadeInsertNextWordbox($currentWordbox, displacedChar) {
let $nextWordbox = this.getNextWordbox($currentWordbox);
if ($nextWordbox.length) { // exists
if ($nextWordbox.val().length == $nextWordbox.attr('maxlength')) { // is full
let lastCharBeforeDisplaced = $nextWordbox.val().charAt($nextWordbox.val().length-1);
$nextWordbox.val($currentWordbox.val().slice(0, -1)); // remove last char
this.cascadeInsertNextWordbox($nextWordbox, lastCharBeforeDisplaced);
}
}
$nextWordbox.val(displacedChar + $nextWordbox.val());
},
Upvotes: 4
Views: 3781
Reputation: 103
Found the solution at this link! $forceUpdate() is what was needed. Updated via v-model :
<div v-show="false" :id="`wordLine_`+(n-1)" :data-numWords="wordLines[n-1].length" class="wordLine" style="display:flex; justify-content:center; margin:0 0 25px;">
<div v-for="(wordSize, key2) in wordLines[n-1]">
<div class="wordBox" style="display:flex; color:#f00;">
<v-text-field v-model="wordInputs[n-1][key2]" required class="wordInput" data-isWordInput="1" :stepperStep="n" :rel="key2" :rules="requiredRule" outline single-line dense height="36" @click:clear="wordInputCleared(n-1, key2)" :size="wordSize" :maxlength="wordSize"></v-text-field>
<div v-show="false" class="wordInputSizeRemaining" style="margin:4px 0px 0px 6px;">{{wordSize}}</div>
</div>
</div>
</div>
And :
} else { // insert keyVal at cursor
let lastCharRemoved = $(this).val().slice(0, -1);
_this.wordInputs[$(this).attr('stepperstep')-1][$(this).attr('rel')] = lastCharRemoved.slice(0, $(this)[0].selectionEnd) + keyVal + lastCharRemoved.slice($(this)[0].selectionEnd);
_this.$forceUpdate();
}
Upvotes: 1