Following this question and this other question, I managed to create the flatpickr element and to send data to the backend. The problem is that, although in the Rule
that validates the datetime the passes
method returns false
, the validation error is not shown in the form.
For sake of easy-reading, this is the blade portion for the datepicker:
<div class="mb-3" wire:ignore>
<label for="pickeddatetime" class="form-label">Date and time</label>
<input id="pickeddatetime" class="form-control @error('pickeddatetime') is-invalid @enderror"
type="datetime-local" name="pickeddatetime" placeholder="Pick a date and time"
value="{{ old('pickeddatetime') }}" wire:model.debounce.500ms="pickeddatetime">
@error('pickeddatetime')
<p class="invalid-feedback">{{ $errors->first('pickeddatetime') }}</p>
@enderror
</div>
I believe it is due to the wire:ignore
directive (used to make flatpickr work with Livewire) preventing any change in the DOM but, again, I'm still learning and thus be completely wrong.
I moved wire:ignore
inside the input
field, and that's the only change I made in the Blade file. There are no other wire:ignore
in there, and the @livewireScripts
is in the layout file (I can see the scripts in the DOM of the Livewire component).
The validation goes as follows: when the datetime is selected, the updatedPickeddatetime
is called (and indeed it is)
public function updatedPickeddatetime($value)
{
$rules = $this->rules();
$rules['pickeddatetime'][] = new TimeSlotEmployeeRule($this->employee_id);
$this->validateOnly('pickeddatetime', $rules);
}
In the TimeSlotEmployeeRule
the passes
method returns false
(for testing purposes).
I placed some strategic dd
s inside the validateOnly
method, and i can see that the ValidationException
is thrown and the ErrorBag
contains the expected message.
Yet, the @error
directive (for the p
element) isn't triggered and the element is not shown.
Apparently, the problem was related, but laying somewhere else: the @error
directive works fine, but I noticed that in the DOM the p
was set as display:none
. This, I think, is related to the fact that the input doesn't get its is-invalid
class, and thus the invalid-feedback
gets hidden.
I therefore changed it to <p class="invalid-feedback d-block">
(as suggested here) and it works!
You're right, the wire:ignore
on the parent div makes Livewire ignore any updates to that part of the DOM. It will never change anything inside of it.
So, to make the paragraph show, simply move the wire:ignore
down on the input itself.
<div class="mb-3">
<label for="pickeddatetime" class="form-label">Date and time</label>
<input id="pickeddatetime" wire:ignore.self class="form-control @error('pickeddatetime') is-invalid @enderror"
type="datetime-local" name="pickeddatetime" placeholder="Pick a date and time"
value="{{ old('pickeddatetime') }}" wire:model.debounce.500ms="pickeddatetime">
@error('pickeddatetime')
<p class="invalid-feedback">{{ $errors->first('pickeddatetime') }}</p>
@enderror
</div>
You will still need wire:ignore
or wire:ignore.self
on the input, as the Flatpickr library will modify and maintain state of the actual input.
This only solves half of your issue though, as you will still not get the class is-invalid
applied when the validation for that property fails. To achieve this, either put the class on a wrapper, and then apply CSS in such a way that it'll be put on the input, or else you would need some sort of listener or change-event on the Flatpickr instance, and then check if the validation failed before applying or removing the class on the input, meaning that you apply it with JavaScript.