-
-
Save jonneroelofs/b4be067329cb12777c4fcf2658013bc2 to your computer and use it in GitHub Desktop.
<div x-data="datepicker(@entangle($attributes->wire('model')))" class="relative"> | |
<div class="flex flex-col"> | |
<label>Date</label> | |
<div class="flex items-center gap-2"> | |
<input type="text" x-ref="myDatepicker" x-model="value"> | |
<span class="cursor-pointer underline" x-on:click="reset"> | |
<x-icon.x></x-icon.x> | |
</span> | |
</div> | |
</div> | |
</div> | |
@once | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css"> | |
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script> | |
<script> | |
document.addEventListener('alpine:init', () => { | |
Alpine.data('datepicker', (model) => ({ | |
value: model, | |
init(){ | |
this.pickr = flatpickr(this.$refs.myDatepicker, {}) | |
this.$watch('value', function(newValue){ | |
this.pickr.setDate(newValue); | |
}.bind(this)); | |
}, | |
reset(){ | |
this.value = null; | |
} | |
})) | |
}) | |
</script> | |
@endonce |
<div class="bg-dark"> | |
<div class="grid place-items-center min-h-screen"> | |
<div class="shadow rounded p-4 border bg-white h-[278px] flex flex-col gap-4"> | |
<h1 class="text-xl font-semibold text-gray-700">Event form</h1> | |
<div class="space-y-4"> | |
<x-datepicker label="Starts at" wire:model="event.starts_at"> | |
</x-datepicker> | |
<x-datepicker label="Ends at" wire:model="event.ends_at"> | |
</x-datepicker> | |
</div> | |
<div> | |
<button | |
class="bg-success-500 text-white px-2 py-1 rounded" | |
wire:click="startToday()" | |
> | |
Start Today | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> |
<?php | |
namespace App\Http\Livewire; | |
use App\Models\Event; | |
use Livewire\Component; | |
class EventForm extends Component | |
{ | |
public $event; | |
public function rules() | |
{ | |
return [ | |
'event.starts_at' => ['required'], | |
'event.ends_at' => ['required'], | |
]; | |
} | |
public function mount() | |
{ | |
$this->event = Event::make(); | |
} | |
public function startToday() | |
{ | |
$this->event->starts_at = today()->format('Y-m-d'); | |
$this->event->ends_at = today()->format('Y-m-d'); | |
} | |
public function render() | |
{ | |
return view('livewire.event-form'); | |
} | |
} |
Incredible how complicated this is.
I have managed to get it to work in my project, but not if I add options to the flatpicker init.
For some reason it won't format the date and just shows a blank.
{dateFormat: 'Y-m-d', altFormat: 'Y-m-d', altInput: true, locale: 'es'}
@davisngl do you have an example?
Thanks for wait, not sure why I didn't get notification for this.
I solved it like so and it seems to work with both Livewire and just Alpine:
// boilerplate code before...
this.$watch(
"value",
function (newDate) {
pickr.setDate(newDate);
}.bind(this)
);
window.addEventListener("newDate", (e) => {
// Dirty workaround to set min-dates for dependant pickers.
// It works by passing through new min date and receiver.
// Since Flatpickr doesn't support dynamic properties, it should
// just get rebuilt.
const {
detail: { receiver },
} = e;
const {
detail: { date },
} = e;
if (this.$el.firstElementChild.name !== receiver) {
return;
}
pickr = flatpickr(this.$refs.datepicker, {
...config,
...{ minDate: date },
});
});
},
//...
}));
This is how I've got it working (with some help from Copilot):
<div x-data="datepicker(@entangle($attributes->wire('model')))" class="relative">
<div class="flex flex-col">
<div>
<input type="date" x-ref="myDatepicker" x-model="value" placeholder="dd-mm-yyyy"
class="block w-full rounded-md border-0 py-2 pl-10 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
>
<span class="cursor-pointer underline" x-on:click="reset">
</span>
</div>
</div>
</div>
@once
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('datepicker', (model) => ({
value: model,
init(){
this.pickr = flatpickr(this.$refs.myDatepicker, {
// Options here
minDate: "today",
dateFormat: "Y-m-d"
});
this.$watch('value', function(newValue){
this.pickr.setDate(newValue);
}.bind(this));
},
reset(){
this.value = null;
}
}))
})
</script>
@endonce
Hope this helps someone :-)
I've run into an issue with multiple datepickers on the same page - they both preload with the same value when the component properties both have an existing values. I think it's something to do with the x-model being the same (x-model="value") for both datepickers.
I've spent hours trying to solve this with my very limited alpine skills :(
<div wire:ignore x-data="datepicker(@entangle($attributes->wire('model')))" class="relative">
<x-input class="mt-1 block w-full" x-ref="myDatepicker" x-model="value" id="{{ rand() }}" />
</div>
@once
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('datepicker', (model) => ({
value: model,
init(){
this.pickr = flatpickr(this.$refs.myDatepicker, {dateFormat:'d/m/Y'})
this.$watch('value', function(newValue){
this.pickr.setDate(newValue);
}.bind(this));
},
reset(){
this.value = null;
}
}))
})
</script>
@endonce
<div class="mb-5" wire:ignore>
<x-label value="Date" />
<x-datepicker wire:model="date" />
<x-input-error for="date" class="mt-2" />
</div>
<div class="mb-5" wire:ignore>
<x-label value="Today" />
<x-datepicker wire:model="today" />
<x-input-error for="today" class="mt-2" />
</div>
@davisngl do you have an example?