I use livewire 3 to build a form using dinamyc element. So I can add multiple row element inside my form.
When I run on Manual Page Reload
or navigate link click (page reload)
without wire:navigate
it run smoothly.
But when I use wire:navigate
for the link, I found error when initial datepicker. My datepicker can multiple elements, because my form can add dinamicly using add button and I must init for using this.
The error is when I navigate to another page, and back to page using datepicker, error like
Uncaught TypeError: window.Livewire.find(...) is undefined
How to fic this?
My view code here :
<button type="button" class="btn btn-primary" wire:click="addRow">Add New</button>
<script>
function goBack(e) {
window.history.back();
}
</script>
@script
<script>
document.addEventListener('DOMContentLoaded', function () {
console.log("DOMContentLoaded");
initializeDatepickers();
});
Livewire.hook('element.init', ({ component, el }) => {
console.log("element.init");
if (document.querySelectorAll('[id^="date_"]').length) {
initializeDatepickers();
}
});
function initializeDatepickers() {
// Check if rows exist in the Livewire component
const rows = @this.get('rows');
if (!rows || !Array.isArray(rows)) {
return;
}
// Iterate through each row and initialize datepicker
rows.forEach((row, index) => {
const datepickerId = `#date_${index}`;
const $datepickerElement = $(datepickerId);
// Ensure the datepicker element exists before initializing
if ($datepickerElement.length) {
// Destroy existing datepicker to avoid conflicts
if ($datepickerElement.data('datepicker')) {
$datepickerElement.datepicker('destroy');
}
$datepickerElement.datepicker({
todayHighlight: true,
orientation: "bottom left",
autoclose: true,
format: "dd-mm-yyyy"
}).on("changeDate", function (e) {
@this.set(`rows.${index}.date`, e.format());
});
}
});
}
// Initialize the single datepicker
$('#tanggal_ajuan').datepicker({
todayHighlight: true,
orientation: "bottom left",
autoclose: true,
format: "dd-mm-yyyy"
}).on("changeDate", function (e) {
$wire.tanggal_ajuan = e.format();
});
</script>
@endscript
My component code :
<?php
namespace AppLivewireKontrak;
use AppModelsOutlet;
use LivewireComponent;
use LivewireWithFileUploads;
use LivewireAttributesTitle;
use LivewireAttributesValidate;
use IlluminateSupportFacadesDB;
class EventKontrak extends Component
{
use WithFileUploads;
#[Title('Kontrak Event')]
public $outlet = null;
public $kelas_event = "";
public $tanggal_ajuan = "";
public $nama_talent = "";
public $tipe_event = "";
public $publikasi_event = "";
public $rows = [];
protected function rules()
{
$rules = [
'kelas_event' => 'required',
'tanggal_ajuan' => 'required',
'nama_talent' => 'required',
'tipe_event' => 'required',
'publikasi_event' => 'required|file',
'rows.*.pic_event' => 'required|string|max:255',
'rows.*.date' => 'required|date',
'rows.*.day' => 'required|string|max:255',
'rows.*.venue' => 'required|string|max:255',
'rows.*.tier' => 'required|string|max:255',
'rows.*.ro' => 'nullable|string|max:255',
'rows.*.ao' => 'nullable|string|max:255',
'rows.*.brand' => 'nullable|string|max:255',
'rows.*.jam_kerja' => 'required|string|max:255',
'rows.*.team' => 'required|string|max:255',
'rows.*.fp' => 'required|string|max:255',
'rows.*.tl' => 'required|string|max:255',
'rows.*.wd' => 'required|string|max:255',
'rows.*.car' => 'required|string|max:255',
'rows.*.target_contact' => 'required|integer',
'rows.*.target_trial' => 'required|integer',
'rows.*.agency' => 'required|string|in:KOMPLIT,OHP',
'rows.*.jenis_event' => 'required|string|max:255',
'rows.*.note' => 'nullable|string|max:255',
'rows.*.keterangan_event' => 'required|string|max:255',
'rows.*.keterangan' => 'required|string|max:255',
];
return $rules;
}
public function render()
{
return view('livewire.kontrak.event-kontrak');
}
public function mount($uuid)
{
$this->outlet = Outlet::with(['detail', 'regional', 'area', 'horecaGroup', 'brand', 'installationUnitBranding'])
->whereUuid($uuid)
->firstOrFail();
$defaultRo = $this->outlet->regional->name;
$defaultAo = $this->outlet->area->name;
$defaultBrand = $this->outlet->brand->merek;
$this->rows[] = $this->initializeRow($defaultRo, $defaultAo, $defaultBrand);
}
private function initializeRow($ro = '', $ao = '', $brand = '')
{
return [
'pic_event' => '',
'date' => '',
'day' => '',
'venue' => '',
'tier' => '',
'ro' => $ro,
'ao' => $ao,
'brand' => $brand,
'jam_kerja' => '',
'team' => '',
'fp' => '',
'tl' => '',
'wd' => '',
'car' => '',
'target_contact' => '',
'target_trial' => '',
'agency' => '',
'jenis_event' => '',
'note' => 'ON THE EVENT',
'keterangan_event' => '',
'keterangan' => '',
];
}
public function addRow()
{
// Get the default value for 'ro'
$defaultRo = $this->outlet->regional->name;
$defaultAo = $this->outlet->area->name;
$defaultBrand = $this->outlet->brand->merek;
// Add a new row with the default value
$this->rows[] = $this->initializeRow($defaultRo, $defaultAo, $defaultBrand);
}
public function removeRow($index)
{
unset($this->rows[$index]);
$this->rows = array_values($this->rows); // Re-index the array
}
public function submit()
{
$validated = $this->validate([
'rows.*.pic_event' => 'required|string',
'rows.*.date' => 'required|date',
'rows.*.day' => 'required|string',
'rows.*.venue' => 'required|string',
'rows.*.tier' => 'required|string',
'rows.*.jam_kerja' => 'required|string',
'rows.*.team' => 'required|string',
'rows.*.fp' => 'required|string',
'rows.*.tl' => 'required|string',
'rows.*.wd' => 'required|string',
'rows.*.car' => 'required|string',
'rows.*.target_contact' => 'required|integer',
'rows.*.target_trial' => 'required|integer',
'rows.*.agency' => 'required|string',
'rows.*.jenis_event' => 'required|string',
'rows.*.note' => 'nullable|string',
'rows.*.keterangan_event' => 'nullable|string',
'rows.*.keterangan' => 'nullable|string',
],[
'rows.*.pic_event.required' => 'PIC Event field is required.',
'rows.*.date.required' => 'Date field is required.',
'rows.*.day.required' => 'Day field is required.',
'rows.*.venue.required' => 'Venue field is required.',
'rows.*.tier.required' => 'Tier field is required.',
'rows.*.jam_kerja.required' => 'Jam Kerja field is required.',
'rows.*.team.required' => 'Team field is required.',
'rows.*.fp.required' => 'FP field is required.',
'rows.*.tl.required' => 'TL field is required.',
'rows.*.wd.required' => 'WD field is required.',
'rows.*.car.required' => 'Car field is required.',
'rows.*.target_contact.required' => 'Target Contact field is required.',
'rows.*.target_trial.required' => 'Target Trial field is required.',
'rows.*.agency.required' => 'Agency field is required.',
'rows.*.jenis_event.required' => 'Jenis Event field is required.',
'rows.*.note.required' => 'Note field is required.',
'rows.*.keterangan_event.required' => 'Keterangan Event field is required.',
'rows.*.keterangan.required' => 'Keterangan field is required.',
]);
}
}
How to make link with wire:navigate
and the all elements re-initiated?