how to scroll to first validation error message in livewire laravel

Viewed 1986

I am new in livewire. i am working on registration process of user. Register form is quite big and validations also working fine to me. The problem is when user submits the form validations came but user not able to see because submit button is at bottom and form is at top.

When i manually scroll to top error message is displaying. So what i want when user submits the form its will automatically go to first error message. Here is my code:

<form wire:submit.prevent="userRegister">
<div class="row">
    <div class="col-md-3">
        <label>First Name *</label>
    </div>
    <div class="col-md-9">
        <input type="text" wire:model="register.first_name" placeholder="Enter First Name" required>
        @error('register.first_name') <span class="text-danger">{{ $message }}</span> @enderror
    </div>
</div>
<div class="row">
    <div class="col-md-3">
        <label>Last Name *</label>
    </div>
    <div class="col-md-9">
        <input type="text" wire:model="register.last_name" placeholder="Enter Last Name">
        @error('register.last_name') <span class="text-danger">{{ $message }}</span> @enderror
    </div>
</div>
<div class="row">
    <div class="col-md-3">
        <label>Test 1 Name *</label>
    </div>
    <div class="col-md-9">
        <input type="text" wire:model="register.test1_name" placeholder="Enter Last Name">
    </div>
</div>
<div class="row">
    <div class="col-md-3">
        <label>Test 2 Name *</label>
    </div>
    <div class="col-md-9">
        <input type="text" wire:model="register.test2_name" placeholder="Enter Last Name">
    </div>
</div>
<div class="row">
    <div class="col-md-3">
        <label>Test 3 Name *</label>
    </div>
    <div class="col-md-9">
        <input type="text" wire:model="register.test3_name" placeholder="Enter Last Name">
    </div>
</div>
<div class="row">
    <div class="col-md-3"></div>
    <div class="col-md-9">
        <!--<input type="submit" value="Edit" class="edt-sb">-->
        <input wire:click="userRegister" type="submit" value="Submit" class="edt-sv">
    </div>
</div>
</form>

My Register.php

<?php

namespace App\Http\Livewire;

use Livewire\Component;
class Register extends Component
{
public $register;
protected $rules = [
    'register.first_name' => 'bail|required|max:50',
    'register.last_name' => 'bail|required|max:50',
];

protected $messages = [
    'register.first_name.required' => 'Please enter first name',
];

public function userRegister(){
    $this->validate();
}

I want when user submits the form it will immediately scroll to first error message. Currently my validations work perfects for me. Do i need to use alpine js? for this.

3 Answers

Livewire errors will be saved in $errors bag so probably you can add an id to each field in your form and use alpinejs to focus the first element with the id present in the errors bag, something like:

        <div x-data="{
                'errors': {{ json_encode(array_keys($errors->getMessages())) }},
                focusField(input) {
                    fieldError = document.getElementById(input);
                    if (fieldError) {
                        fieldError.focus({preventScroll:false});
                    }
                },
            }"
             x-init="() => { $watch('errors', value => focusField(value[0])) }">
            
                    <input id="register.test3_name" type="text" wire:model="register.test3_name" placeholder="Enter Last Name">
        </div>

I nearly faced the same issue but with success message not error messages, for error messages I used updated(), they are shown on real time for user while filling the fields.

My Class Component :

class FormSubmissions extends Component
{
    public $city;
    public $fullname;

    protected $rules = [
        'city' => 'required',
        'fullname' => 'required',
    ];

    public $successMessage;

    public function updated($propertyName)
    {
        $this->validateOnly($propertyName);
    }

    public function submitForm()
    {
        $submission = $this->validate();



        $this->successMessage = trans('site.success');


        $this->resetForm();
    }


    public function resetForm()
    {
        $this->city = '';
        $this->fullname = '';
    }

}

My Blade template :

<div id="formSection" class="form-wrapper">
    @if ($successMessage)
        <div  class="alert alert-success alert-dismissible fade show" role="alert">
            {{ $successMessage }}
            <button  wire:click="$set('successMessage', null)" type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        <script>
            var elmnt = document.getElementById("formSection");
            elmnt.scrollIntoView();
        </script>
    @endif
    <form wire:submit.prevent="submitForm" action="/" method="POST">
    ...

</div>

So the small script added with success message allowed me to scroll back to top of my form Section #formSection.

If you are using <x-jet-input-error/> component for displaying errors, you can just modify resources/views/vendor/jetstream/components/input-error.blade.php (make sure you have published livewire views) file to below code:

@props(['for'])

<span x-data="{hasError: '{{$errors->get($for)[0] ?? ''}}' }"
     x-init="()=> { $watch('hasError', (value)=> {
            let errorDiv = document.getElementsByClassName('invalid-feedback')[0];
            if(errorDiv){
                errorDiv.scrollIntoView({behavior: 'smooth', block: 'center', inline: 'nearest'});
            }
    })}">
    @error($for)
        <span {{ $attributes->merge(['class' => 'invalid-feedback d-block']) }} role="alert" style="font-size: inherit">
            <strong>{{ $message }}</strong>
        </span>
    @enderror
</span>

Explanation : we use alpine to watch for changes in the validation message for the "$for" field. As soon as it changes (validation message shows up or vanishes), it looks for the error block and scrolls to it

Related