Search code examples
laravel-livewirealpine.js

What's the problem with x-trap in Alpine JS on move between inputs?


I have an OTP input that consists of 8 one digit inputs this image and when I move between these digit inputs by x-on:keyup , always the first input is focused and value is selected for a moment then moves to next input.

to get the problem clearly, also watch this video

Component:

<div class="flex w-full content-center">
    <form x-transition wire:submit.prevent.throttle.1000ms="verifyotp()" class="w-full">
        <div x-data="{digitinputnumber : 1}" class="w-full px-4 grid gap-4">
            <div class="flex items-center mb-4 dark:text-white">
                <span class="bg-slate-100 dark:bg-gray-500 rounded p-1 ml-1">
                    <x-icon.shield-check/>
                </span>
                <h3>{{ __('messages.login.enter-otp') }}</h3>
            </div>

            <div class="flex gap-2 ltr justify-center">

                <div>
                    <input x-model="d1" select-none  x-on:click="digitinputnumber = 1" x-on:keyup="if($event.key != 'Backspace' && 0 <= d1 && d1 <= 9) {digitinputnumber = digitinputnumber + 1} else {}" x-trap="digitinputnumber == 1 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
                <div>
                    <input x-model="d2" x-on:click="digitinputnumber = 2" x-on:keyup="if($event.key != 'Backspace' && 0 <= d2 && d2 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 2 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
                <div>
                    <input x-model="d3" x-on:click="digitinputnumber = 3" x-on:keyup="if($event.key != 'Backspace' && 0 <= d3 && d3 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap.="digitinputnumber == 3 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
                <div>
                    <input x-model="d4" x-on:click="digitinputnumber = 4" x-on:keyup="if($event.key != 'Backspace' && 0 <= d4 && d4 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 4 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
                <div>
                    <input x-model="d5" x-on:click="digitinputnumber = 5" x-on:keyup="if($event.key != 'Backspace' && 0 <= d5 && d5 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 5 ? true : false"x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
                <div>
                    <input x-model="d6" x-on:click="digitinputnumber = 6" x-on:keyup="if($event.key != 'Backspace' && 0 <= d6 && d6 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 6 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
                <div>
                    <input x-model="d7" x-on:click="digitinputnumber = 7" x-on:keyup="if($event.key != 'Backspace' && 0 <= d7 && d7 <= 9) {digitinputnumber = digitinputnumber + 1} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 7 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
                <div>
                    <input x-model="d8" x-on:click="digitinputnumber = 8" x-on:keyup="if($event.key != 'Backspace' && 0 <= d8 && d8 <= 9) {} else {digitinputnumber = digitinputnumber - 1}" x-trap="digitinputnumber == 8 ? true : false" x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>

            </div>
        </div>
    </form>
</div>

I had not get answer in git hub discussions of livewire and alpine, also I couldn't find answers in documentation or web forums.


Solution

  • I actually don't understand why my code was not working, but I changed to code below and every thing OK!

    I should use x-ref and focus() to handle this type of input, maybe it's bug of Alpine JS or some thing I don't now.

    Also you can use x-for to make it better, but I prefer not to do.

    <div class="flex w-full content-center">
    <form x-transition wire:submit.prevent.throttle.1000ms="verifyotp()" class="w-full">
        <div class="w-full px-4 grid gap-4">
            <div class="flex items-center mb-4 dark:text-white">
                <span class="bg-slate-100 dark:bg-gray-500 rounded p-1 ml-1">
                    <x-icon.shield-check/>
                </span>
                <h3>{{ __('messages.login.enter-otp') }}</h3>
            </div>
    
            <div class="flex gap-2 ltr justify-center">
    
                <div>
                    <input x-ref="d1" x-on:keyup="if($event.key != 'Backspace') {$refs.d2.focus()} else {}"  x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg" autofocus>
                </div>
    
                <div>
                    <input x-ref="d2" x-on:keyup="if($event.key != 'Backspace') {$refs.d3.focus()} else {$refs.d1.focus()}"  x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
    
                <div>
                    <input x-ref="d3" x-on:keyup="if($event.key != 'Backspace') {$refs.d4.focus()} else {$refs.d2.focus()}"  x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
    
                <div>
                    <input x-ref="d4" x-on:keyup="if($event.key != 'Backspace') {$refs.d5.focus()} else {$refs.d3.focus()}"  x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
    
                <div>
                    <input x-ref="d5" x-on:keyup="if($event.key != 'Backspace') {$refs.d6.focus()} else {$refs.d4.focus()}"  x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
    
                <div>
                    <input x-ref="d6" x-on:keyup="if($event.key != 'Backspace') {$refs.d7.focus()} else {$refs.d5.focus()}"  x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
    
                <div>
                    <input x-ref="d7" x-on:keyup="if($event.key != 'Backspace') {$refs.d8.focus()} else {$refs.d6.focus()}"  x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
                
                <div>
                    <input x-ref="d8" x-on:keyup="if($event.key != 'Backspace') {} else {$refs.d7.focus()}"  x-mask="9" type="text" class="p-2 w-12 aspect-square text-center ltr text-xl rounded-lg">
                </div>
    
            </div>
        </div>
    </form>