Search code examples
laravellaravel-livewire

Livewire validateOnly with validate in the same component


I have a little problem with the data validation with livewire ( laravel ).

I noticed that when I set up the validation in real time ( validateOnly() ), the information entered in the form is validated in real time. At this level everything is fine.

But when I click on the button to submit the form (even though the form contains errors), the form is unfortunately sent to my function defined in the wire:submit.

So my question is : is it possible to revalidate the information in the wire:submit method that receives the data after the form is submitted ? If so, how can I do that?

PS: I tried to set the validate method in my wire:submit function but nothing happens. It blocks the form from being submitted but it doesn't give me an error .

My source code :

<?php
class UserProfile extends Component
{
    use WithFileUploads;

    public $countries = [];
    public $profile = [];

    protected function rules() {
        if ( !LivewireUpdateProfileRequest::authorize() ) {
            return abort(403, "Your are not authorized to make this request !");
        }
        $rules = LivewireUpdateProfileRequest::rules();

        if ( !empty($this->profile['phone']) ) {
            $rules['profile.phone'] = [ 'required', 'phone_number:' . $this->profile['phone'] ];
        }

        return $rules;
    }


    public function mount()
    {
        $this->countries = Countries::all();
        $this->profile = Auth::user()->toArray();
    }


    public function updateUserProfile()
    {
        $validatedData = $this->validate();
        dd( $validatedData );
    }

    public function updated($key, $value)
    {
        $this->validateOnly($key);
    }


    public function render()
    {
        return view('livewire.user-profile');
    }
}

Html source :

 <form action="" method="POST" wire:submit.prevent="updateUserProfile">
    <input name="profile.email" type="email" wire:model="profile.email" />
    @error('profile.email') {{ $message }} @enderror

    <input name="profile.phone" type="tel" wire:model="profile.phone" />
    @error('profile.phone') {{ $message }} @enderror
</form>

Here is LivewireUpdateProfileRequest content :

<?php

namespace App\Http\Requests\Web;

use Illuminate\Foundation\Http\FormRequest;

class LivewireUpdateProfileRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public static function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public static function rules()
    {
        return [
            'profile' => ['required', 'array', 'size:10'],
            'profile.firstname' => ['required', 'string'],
            'profile.lastname' => ['required', 'string'],
            'profile.email' => ['required', 'email'],
            'profile.phone' => ['required', 'phone_number:33'],
            'profile.gender' => ['required', 'gender'],
            'profile.image' => ['sometimes', 'image', 'mimes:png,jpg,jpeg'],
            'profile.address' => ['required', 'string'],
            'profile.city' => ['required', 'string'],
            'profile.country_id' => ['required', 'exists:countries,id'],
            'profile.birth_at' => ['required', 'date', 'min_age:18'],
        ];
    }
}

Solution

  • Usually in your saving method you would run validation once more for all fields. The livewire docs share this example:

    Livewire Component:

    class ContactForm extends Component
    {
        public $name;
        public $email;
    
        protected $rules = [
            'name' => 'required|min:6',
            'email' => 'required|email',
        ];
    
        public function updated($propertyName)
        {
            $this->validateOnly($propertyName);
        }
    
        public function saveContact()
        {
            $validatedData = $this->validate();
    
            Contact::create($validatedData);
        }
    }
    

    With this HTML:

    <form wire:submit.prevent="saveContact">
        <input type="text" wire:model="name">
        @error('name') <span class="error">{{ $message }}</span> @enderror
    
        <input type="text" wire:model="email">
        @error('email') <span class="error">{{ $message }}</span> @enderror
    
        <button type="submit">Save Contact</button>
    </form>
    

    This should validate the inputs near-realtime using the updated-method and on submit using the saveContact-method.

    If you could share your code, we could debug it easier.

    Source: https://laravel-livewire.com/docs/2.x/input-validation#real-time-validation