Search code examples
laravel-livewire

How in Livewire to tie $errors->all()) to my Volt class?


On a Laravel 11 / Livewire 3 site I use Volt classes to render 1 element block, like in resources/views/livewire/common/controls/input_text.blade.php I have code :

<?php

use Livewire\Volt\Component;
use Livewire\Attributes\Modelable;

new class extends Component {
    #[Modelable]
    public $form;
    public string $formattedValue = '';
    public string $fieldName = '';
    public string $label = '';
    public ?string $placeholder = '';
    public ?int $maxlength = 0;
};
?>

<div class="editor_field_block_wrapper d2">

    <div class="editor_field_block_device_splitter">
        <div class="w-4/12 pb-0 pl-2 md:pt-3 ">
            <label for="{{ $fieldName }}" class="editor_field_block_device_label">
                {{ !empty($label) ? $label: \Str::ucfirst(\Str::replace('_', ' ', $fieldName)) }}:
            </label>
        </div>
        <div class="p-2 w-full">
            <input id="{{ $fieldName }}" name="{{ $fieldName }}" type="text"
                   class="editor_form_input"
                   @if(!empty($maxlength)) maxlength="{{ $maxlength }}" @endif
                   wire:model="form.{{ $fieldName }}"
                   autocomplete="off"
                   @if(!empty($placeholder)) placeholder="{{ $placeholder }}" @endif
            />
            @error('form.' . $fieldName)
            <span class="error_text">{{$message}}</span>
            @enderror
        </div>
    </div>
</div>

and I use this Volt class in Blade file as :

<livewire:common.controls.input_text fieldName="name" wire:model="form" :maxlength="50" key="nameInputText" /> I use form object for this editor and I pass it to Volt class and use #[Modelable] attribute.

But when submitting the form validation errors are raised the block :

        @error('form.' . $fieldName)
            <span class="error_text">{{$message}}</span>
        @enderror

Does not not work. Checking $errors->all()) and putting it in parent blade file all errors are shown OK.

But in Volt class these errors are not shown. Any idea how to tie $errors->all()) to my Volt class ?

a) Livewire has Modelable attribute (https://livewire.laravel.com/docs/nesting#binding-to-child-data-using-wiremodel). Are there something like that for validation errors like "errorable" ?

b) Volt classes can catch Livewire events : if there is a way when livewire validation fails to trigger custom event ?

"laravel/framework": "^11.9",
"livewire/livewire": "^3.5",
"livewire/volt": "^1.6",

Update

I found this https://github.com/livewire/livewire/discussions/7460#discussioncomment-8095059 branch and try to do :

public function update(Request $request)
{
        ...
        try {
            $this->form->validate($validationRulesArray, $validationMessages());
        } catch (Throwable $e) {
            // I my log file I do not find these 2 lines
            \Log::info( ' -1 Throwable $e::');
            \Log::info($e);
            $this->dispatch('customValidationError', ['e' => $e]);
            throw $e;
        }

        $this->form->updated_at = Carbon::now(ConfigValueEnum::get(ConfigValueEnum::TIMEZONE));
        ...

and in my Volt class try to catch this custom error :

<?php

use Livewire\Volt\Component;
use Livewire\Attributes\Modelable;
use function Livewire\Volt\{on};

new class extends Component {
    #[Modelable]
    public $form;
    public string $formattedValue = '';
    ...
};

on(['customValidationError' => function ($options) {
    dd('customValidationError $options::' .$options);
    ...
}]);

?>

But I failed to catch validation error. Can I do it somehow ?


Solution

  • When you run validate method inside your parent component, you fill parent component error bag with list of errors. The problem is that your child component, which has a Modelable form, doesn't have access to this data.

    I think, there are two solutions for this issue. You can try to dispatch an event and add errors related to that form there. Or you can create separate blade component for errors and include it right after your livewire component.