livewire modal closes after update

Is there a way to prevent a modal from automatically closing when the livewire content inside updates? I have a calendar but when I change month, it closes the modal
Solution:
So I decided to just boycott the modal approach and added the widget directly to my View Page, make things easier
Jump to solution
19 Replies
Dennis Koch
Dennis Koch3mo ago
I don't think that should happen.
Jamie Cee
Jamie CeeOP3mo ago
As in it already shouldn't be happening (some issue somewhere). Or my use case is wrong? 🤔
Dennis Koch
Dennis Koch3mo ago
I don't think modal should close with Livewire updates. Live forms work the same way. So probably some issues with your specific case.
Jamie Cee
Jamie CeeOP3mo ago
Thats actually a good point. Hm, something else must be the cause then yeah Cheers
Dennis Koch
Dennis Koch3mo ago
Maybe share some code?
Jamie Cee
Jamie CeeOP3mo ago
<div class="gap-4" wire.ignore.self>
@if ($record->instructorAvailabilities->isEmpty())
<div class="p-4 text-center text-gray-500">
No availability periods set for this instructor.
</div>
@endif

<div class="hidden md:block" wire:ignore.self>
@livewire('availability-widget', ['record' => $record])
</div>

<div class="block md:hidden">
@foreach ($record->instructorAvailabilities as $availability)
@php
$days = collect($availability->days_of_week)->map(function ($day) {
$map = [1 => 'Mon', 2 => 'Tue', 3 => 'Wed', 4 => 'Thu', 5 => 'Fri', 6 => 'Sat', 7 => 'Sun'];
return $map[$day] ?? $day;
})->join(', ');

$startDate = \Carbon\Carbon::parse($availability->start_date)->format('j M Y');
$endDate = \Carbon\Carbon::parse($availability->end_date)->format('j M Y');
@endphp
<div class="p-4 bg-white rounded-lg shadow">
<div><strong>Available:</strong> {{ $days }}</div>
<div><strong>From:</strong> {{ $startDate }} <strong>To:</strong> {{ $endDate }}</div>

@if ($availability->time_blocks && is_iterable($availability->time_blocks))
<div>
<strong>Time Blocks:</strong>
<ul class="list-none ml-4">
@foreach ($availability->time_blocks as $block)
<li>{{ $block['start'] ?? '' }} - {{ $block['end'] ?? '' }}</li>
@endforeach
</ul>
</div>
@endif
</div>

@endforeach
</div>
</div>
<div class="gap-4" wire.ignore.self>
@if ($record->instructorAvailabilities->isEmpty())
<div class="p-4 text-center text-gray-500">
No availability periods set for this instructor.
</div>
@endif

<div class="hidden md:block" wire:ignore.self>
@livewire('availability-widget', ['record' => $record])
</div>

<div class="block md:hidden">
@foreach ($record->instructorAvailabilities as $availability)
@php
$days = collect($availability->days_of_week)->map(function ($day) {
$map = [1 => 'Mon', 2 => 'Tue', 3 => 'Wed', 4 => 'Thu', 5 => 'Fri', 6 => 'Sat', 7 => 'Sun'];
return $map[$day] ?? $day;
})->join(', ');

$startDate = \Carbon\Carbon::parse($availability->start_date)->format('j M Y');
$endDate = \Carbon\Carbon::parse($availability->end_date)->format('j M Y');
@endphp
<div class="p-4 bg-white rounded-lg shadow">
<div><strong>Available:</strong> {{ $days }}</div>
<div><strong>From:</strong> {{ $startDate }} <strong>To:</strong> {{ $endDate }}</div>

@if ($availability->time_blocks && is_iterable($availability->time_blocks))
<div>
<strong>Time Blocks:</strong>
<ul class="list-none ml-4">
@foreach ($availability->time_blocks as $block)
<li>{{ $block['start'] ?? '' }} - {{ $block['end'] ?? '' }}</li>
@endforeach
</ul>
</div>
@endif
</div>

@endforeach
</div>
</div>
So loading the calendar in the @livewire block
Dennis Koch
Dennis Koch3mo ago
Just guessing, can it be related to the wire.ignore? Can you share the calendar? Or is it too much?
Jamie Cee
Jamie CeeOP3mo ago
The calendar is just using guava plugin
class AvailabilityWidget extends CalendarWidget
{
// protected int | string | array $columnSpan = 'full';

protected string $calendarView = 'dayGridMonth';

public User $record;

public function mount(User $record): void
{
$this->record = $record;
}

public function getOptions(): array
{
return [
'slotDuration' => ['hours' => 1],
'hiddenDays' => [],
'dayHeaderFormat' => [
'weekday' => 'short',
'day' => 'numeric',
],
'headerToolbar' => [
'start' => 'today',
'center' => 'prev,title,next',
'end' => '',
],
'buttonText' => [
'today' => __('Today'),
'dayGridMonth' => __('Month'),
'timeGridWeek' => __('Week'),
],
];
}
}
class AvailabilityWidget extends CalendarWidget
{
// protected int | string | array $columnSpan = 'full';

protected string $calendarView = 'dayGridMonth';

public User $record;

public function mount(User $record): void
{
$this->record = $record;
}

public function getOptions(): array
{
return [
'slotDuration' => ['hours' => 1],
'hiddenDays' => [],
'dayHeaderFormat' => [
'weekday' => 'short',
'day' => 'numeric',
],
'headerToolbar' => [
'start' => 'today',
'center' => 'prev,title,next',
'end' => '',
],
'buttonText' => [
'today' => __('Today'),
'dayGridMonth' => __('Month'),
'timeGridWeek' => __('Week'),
],
];
}
}
THats all there is in it currently And opening the content in an action modal
Tables\Actions\Action::make('viewInstructorAvailability')
->label('Availability')
->icon('heroicon-o-calendar')
->color('calendar_action')
->visible(fn($record) => $record->hasRole(\App\Enums\BaseRolesEnum::INSTRUCTOR))
->modalHeading('Instructor Availability')
->modalSubmitAction(false)
->modalCancelActionLabel('Close')
->modalWidth('7xl')
->closeModalByClickingAway(false)
->closeModalByEscaping(false)
->slideOver()
->modalContent(fn($record): View => view('components.availability-widget', [
'record' => $record,
])),
Tables\Actions\Action::make('viewInstructorAvailability')
->label('Availability')
->icon('heroicon-o-calendar')
->color('calendar_action')
->visible(fn($record) => $record->hasRole(\App\Enums\BaseRolesEnum::INSTRUCTOR))
->modalHeading('Instructor Availability')
->modalSubmitAction(false)
->modalCancelActionLabel('Close')
->modalWidth('7xl')
->closeModalByClickingAway(false)
->closeModalByEscaping(false)
->slideOver()
->modalContent(fn($record): View => view('components.availability-widget', [
'record' => $record,
])),
Dennis Koch
Dennis Koch3mo ago
Hm, Widgets are just LW components, but maybe it's causing something else. Can you try with a simple LW component, that calls one of it's methods, just for testing?
Jamie Cee
Jamie CeeOP3mo ago
I shall give it a go now
Dennis Koch
Dennis Koch3mo ago
Did you register the widget on that Resource?
Jamie Cee
Jamie CeeOP3mo ago
I dont believe so
Dennis Koch
Dennis Koch3mo ago
You should register them via the public static function getWidgets() method
Jamie Cee
Jamie CeeOP3mo ago
Just added that now, didnt make a difference? As for the livewire test, I cant even get that to work Unable to call component method. Public method [testClick] not found on component The Action
->modalContent(fn($record): View => view('livewire.test-component', [
'record' => $record,
])),
->modalContent(fn($record): View => view('livewire.test-component', [
'record' => $record,
])),
Component
class TestComponent extends Component
{
public function render()
{
return view('livewire.test-component');
}

public function testClick()
{
dd('test');
}
}
class TestComponent extends Component
{
public function render()
{
return view('livewire.test-component');
}

public function testClick()
{
dd('test');
}
}
View:
<div>
<button wire:click="testClick" type="button">Click Me</button>
</div>
<div>
<button wire:click="testClick" type="button">Click Me</button>
</div>
I added this in the boot of my AppServiceProvider as well
Livewire::component('test-component', \App\Livewire\TestComponent::class);
Livewire::component('test-component', \App\Livewire\TestComponent::class);
Ah wait, test one works. So I made a second view, that loads the livewire component with <livewire:component /> So Ill try that with the calendar approach Nevermind, didnt fix it 🤣
Dennis Koch
Dennis Koch3mo ago
You are rendering just the Livewire view. Not the component. Okay, what works, what didn't? 😅 Does the LW component work or does that close the modal, too?
Jamie Cee
Jamie CeeOP3mo ago
the LW component worked. I had the modal content call a view, that view called <livewire:test-component /> which had a button and a click, and the action of the click worked.
Dennis Koch
Dennis Koch3mo ago
Okay, so it's not LW in a modal per se but must have something to do with either the widget or the specific implementation Does ist maybe trigger a full reload?
Jamie Cee
Jamie CeeOP3mo ago
Potentially, but no idea off the top of my head, Ill take a dig through the code Lost in this package, gonna park it up and go on lunch
Solution
Jamie Cee
Jamie Cee3mo ago
So I decided to just boycott the modal approach and added the widget directly to my View Page, make things easier

Did you find this page helpful?