F
Filamentā€¢14mo ago
DrByte

JS lightbox works in infobox but not in modal triggered by Table ViewAction in RelationManager

TLDR: This is about getting Filament's modal to properly call the js after the component is rendered to a modal. (This is not about fslightbox itself: It's working fine in a "Page" rendered by Filament. But Filament's modals won't let it run properly. I'm trying to figure out why.) Details: So I've got this fslightbox component I created by cloning the SpatieMediaLibraryImageEntry component, and basically all it does is pull image URLs for full-size and a smaller conversion size, passing those to the template, and customizes the template to wrap the <img src="(default-src)"> inside an <a href="(lrg-src)" data-fslightbox="lightbox"> element, so that fslightbox can identify the elements to attach itself to. So mostly just markup on the correct URLs to the image assets. It all works great in InfoBox mode when the infobox displays as a Page. (ie: Admin Panel has an Entry Resource to manage the model's entries, each which has one or more images attached via SpatieMediaLib.) So I know my component and template are working correctly. THE PROBLEM But I have another Panel where I display these Entry models as sub-records of Category models, and the RelationManager's "View" button fires the usual \Filament\Tables\Actions\ViewAction ... but only opens as a Modal, not as a Page, which is mostly fine for my needs, with one problem: The fslightbox JS doesn't register these elements. (SYMPTOM: clicking the images opens the a href URL directly, instead of firing the lightbox/gallery) I'm presuming it's because the elements aren't attaching because the modal has created a shadow DOM? I can go to the browser console and manually call refreshFsLightbox(); and the modal's images now work. So that's a "start", but not a solution, not even a workaround. How can I get the modal to run the lightbox js to register the elements itself after the Modal is rendered?
Solution:
Just a shot in the dark, but maybe try ... ```php ->extraAttributes(function (): array { return ['x-data' => new HtmlString('refreshFsLightbox()')];...
Jump to solution
12 Replies
DrByte
DrByteOPā€¢14mo ago
Things I've tried: - adding bespoke <script>refreshFsLightbox();</script> to the bottom of the template component. It gets added to the modal's div, but doesn't make it work. - RenderHooks at various points, for <script>refreshFsLightbox();</script> - FilamentAsset:Js() - customizing the RelationManager's ViewAction to call wire:init like this:
->actions([
Tables\Actions\ViewAction::make()->color('secondary')->button()
->extraAttributes(function (): array {
return ['wire:init' => new HtmlString('refreshFsLightbox();')];
})
->closeModalByClickingAway(false),
])
->actions([
Tables\Actions\ViewAction::make()->color('secondary')->button()
->extraAttributes(function (): array {
return ['wire:init' => new HtmlString('refreshFsLightbox();')];
})
->closeModalByClickingAway(false),
])
Here's the relevant InfoList schema in the RelationManager:
->schema([
\App\Filament\Infolists\Components\FsLightboxEntry::make('photos')
->hiddenLabel()
->collection('entry-photos')
->conversion('preview') // for thumbs
->extraAttributes(function (): array {
return ['wire:init' => new HtmlString('window.refreshFsLightbox();')];
}),
]),
->schema([
\App\Filament\Infolists\Components\FsLightboxEntry::make('photos')
->hiddenLabel()
->collection('entry-photos')
->conversion('preview') // for thumbs
->extraAttributes(function (): array {
return ['wire:init' => new HtmlString('window.refreshFsLightbox();')];
}),
]),
This results in the following Console error:
Alpine Expression Error: $wire.window.refreshFsLightbox is not a function

Expression: "$wire.window.refreshFsLightbox();"

<div class="fi-in-image flex items-center gap-x-2.5" wire:init="window.refreshFsLightbox();">
Alpine Expression Error: $wire.window.refreshFsLightbox is not a function

Expression: "$wire.window.refreshFsLightbox();"

<div class="fi-in-image flex items-center gap-x-2.5" wire:init="window.refreshFsLightbox();">
When I remove the window. prefix, I get other errors:
exception_class: "Livewire\\Exceptions\\MethodNotFoundException"
ā€‹
exception_message: "Unable to call component method. Public method [refreshFsLightbox] not found on component"
exception_class: "Livewire\\Exceptions\\MethodNotFoundException"
ā€‹
exception_message: "Unable to call component method. Public method [refreshFsLightbox] not found on component"
My limited JS/Alpine/Livewire knowledge is showing šŸ˜Š
Solution
cheesegrits
cheesegritsā€¢14mo ago
Just a shot in the dark, but maybe try ...
->extraAttributes(function (): array {
return ['x-data' => new HtmlString('refreshFsLightbox()')];
})
->extraAttributes(function (): array {
return ['x-data' => new HtmlString('refreshFsLightbox()')];
})
cheesegrits
cheesegritsā€¢14mo ago
Or maybe x-init Try and get Alpine to oblige by running refreshFsLightbox()
DrByte
DrByteOPā€¢14mo ago
okay, thanks, will try those ...
DrByte
DrByteOPā€¢14mo ago
One thing I saw when inspecting the XHR to /livewire/update is this .... what is it that calls it as a method? Would that be wire:init?
No description
cheesegrits
cheesegritsā€¢14mo ago
Is that when you had the wire:init version? Which would try and run it as a Livewire method, not JS. Meh, I think. I get confused unless I have the code in front of me. šŸ™‚
DrByte
DrByteOPā€¢14mo ago
Yup, that worked. THANKS! Actually x-init and x-data both seem to work. Is one preferable over the other?
cheesegrits
cheesegritsā€¢14mo ago
I don't think it matters in this case. x-init is probably more appropriate, as that's what you are doing, initializing. Usually you'd use x-init to initialize data in x-data, but you don't actually need any x-data, just leveraging Alpine to fire off some random JS.
DrByte
DrByteOPā€¢14mo ago
Ya, that makes sense. Thanks again.
cheesegrits
cheesegritsā€¢14mo ago
Welcome, glad it worked. I know how frustrating / confusing it can be working with JS in a Livewire / Alpine context sometimes. Don't forget to mark the solution, make it easier for the next person to find the answer.
DrByte
DrByteOPā€¢14mo ago
Update: I ended up moving it out of the extraAttributes[] to just x-init="refreshFsLightbox();" on the component <div> itself. That's where it belongs anyway šŸ™‚
cheesegrits
cheesegritsā€¢14mo ago
Yup.
Want results from more Discord servers?
Add your server