Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

nscott's avatar

Alpine.js lightbox images are not loading

I keep running in circles with my Lightbox component images not loading at all when I loop over them, it just loads the broken image icon. I cam load them all up in a normal foreach loop and see them, but once I run them in a loop in my lightbox they do not come through. So here is the code for my lightbox:

@props(['project', 'galleryImages'])

<div x-data="{ isOpen: false, currentImage: 0, images: {!! json_encode($galleryImages['small']) !!} }">
    <div class="lightbox__grid">
        @foreach($galleryImages['small'] as $key => $image)
            <div class="lightbox__thumbnail" @click="isOpen = true; document.body.classList.add('overflow-hidden'); currentImage = {{ $key }}">
                <img :src="images[{{ $key }}].url" alt="Thumbnail {{ $key }}">
            </div>
        @endforeach
    </div>

    <div x-show="isOpen" class="lightbox__overlay">
        <div class="lightbox__content" x-data="{ currentCaption: '' }">
            <img :src="images[currentImage].url" alt="Large Image">
            <div class="lightbox__caption" x-text="images[currentImage].caption"></div>
            <div class="lightbox__thumbnails">
                @foreach($galleryImages['large'] as $key => $image)
                    <div class="lightbox__thumbnail" @click="currentImage = {{ $key }}; currentCaption = images[{{ $key }}].caption">
                        <img :src="images[{{ $key }}].url" alt="Thumbnail {{ $key }}">
                    </div>
                @endforeach
            </div>
            <button @click="isOpen = false; document.body.classList.remove('overflow-hidden')" class="lightbox__close">&#10005;</button>
            <button @click="currentImage = (currentImage - 1 + images.length) % images.length; $nextTick(() => { currentCaption = images[currentImage].caption })" class="lightbox__button lightbox__prev">&lt;</button>
            <button @click="currentImage = (currentImage + 1) % images.length; $nextTick(() => { currentCaption = images[currentImage].caption })" class="lightbox__button lightbox__next">&gt;</button>
        </div>
    </div>
</div>

I am calling it in my view like this:

<x-lightbox :project="$project" :galleryImages="$galleryImages"></x-lightbox>

In my project controller have loaded the images in my showProject function like this:

public function showProject(Project $project) {

        //Eager load the project relationships
        $project->load('overview', 'testimonials');

        //Get the Hero image
        $heroImage = $this->imageService->getHeroByModelAndId(Project::class, $project->id, "Hero");

         // Get the gallery images for the project
         $galleryImages = $this->imageService->getGalleryImagesForProject($project);
        // dd($galleryImages);
        return view('pages.project', compact('project', 'heroImage', 'galleryImages'));
    }

And I have a service provider like this:

public function getGalleryImagesForProject($project)
    {
        $galleryImages = Media::where('mediaable_type', 'App\Models\Project')
            ->where('mediaable_id', $project->id)
            ->where('type', 'like', 'Gallery%')
            ->get();

        $smallImages = [];
        $largeImages = [];
        foreach ($galleryImages as $image) {
            // Check the type of the image
            if ($image->type === 'Gallery - Small') {
                $smallImages[] = [
                    'url' => asset('img/gallery/' . $image->name),
                    'caption' => $image->img_caption,
                ];
            } elseif ($image->type === 'Gallery - Large') {
                $largeImages[] = [
                    'url' => asset('img/gallery/' . $image->name),
                    'caption' => $image->img_caption,
                ];
            }
        }

        return [
            'small' => $smallImages,
            'large' => $largeImages,
        ];
    }

I ran a regular loop over the small image like this:

 @foreach($galleryImages['small'] as $image)
                <div class="lightbox__thumbnail">
                    <img src="{{ $image['url'] }}" alt="{{ $image['caption'] }}">

                </div>
                @endforeach

And they load just fine. But the loop in the lightbox is not finding the right image names, instead when I open up the console I see this in the image tag:

<img :src="images[0].url" alt="Thumbnail 0" src="">

I am really stuck on this one, sorry for all the code share just trying to cover everything. If I need to add more I can.

*** Edit *** Looking at the console I can see that there is an error:

alpine Expression Error: Unexpected token ';'

Expression: "{ isOpen: false, currentImage: 0, images:  [{"

 <div x-data=​"{ isOpen:​ false, currentImage:​ 0, images:​  [{" url":"http:\ \ localhost:8000\ img\ gallery\ staypanel_forms_installation_laguardia_project_gallery_small_01.webp","caption":""},{"url":"http:\ staypanel_forms_installation_laguardia_project_gallery_small_02.webp","caption":""},{"url":"http:\ staypanel_forms_installation_laguardia_project_gallery_small_03.webp","caption":""},{"url":"http:\ staypanel_forms_installation_laguardia_project_gallery_small_04.webp","caption":""},{"url":"http:\ staypanel_forms_installation_laguardia_project_gallery_small_05.webp","caption":""},{"url":"http:\ staypanel_forms_installation_laguardia_project_gallery_small_06.webp","caption":""},{"url":"http:\ staypanel_forms_installation_laguardia_project_gallery_small_07.webp","caption":""},{"url":"http:\ staypanel_forms_installation_laguardia_project_gallery_small_08.webp","caption":""}] }">​<div class=​"lightbox__grid">​…​</div>​grid<div x-show=​"isOpen" class=​"lightbox__overlay" style=​"display:​ none;​">​…​</div>​</div>​
handleError @ alpinejs.js?v=d17b8359:411
safeAsyncFunction @ alpinejs.js?v=d17b8359:464
generateFunctionFromString @ alpinejs.js?v=d17b8359:468
generateEvaluatorFromString @ alpinejs.js?v=d17b8359:473
normalEvaluator @ alpinejs.js?v=d17b8359:442
evaluateLater @ alpinejs.js?v=d17b8359:432
evaluate @ alpinejs.js?v=d17b8359:428
(anonymous) @ alpinejs.js?v=d17b8359:2692
(anonymous) @ alpinejs.js?v=d17b8359:1158
flushHandlers @ alpinejs.js?v=d17b8359:562
stopDeferring @ alpinejs.js?v=d17b8359:567
deferHandlingDirectives @ alpinejs.js?v=d17b8359:570
initTree @ alpinejs.js?v=d17b8359:753
(anonymous) @ alpinejs.js?v=d17b8359:708
start @ alpinejs.js?v=d17b8359:707
(anonymous) @ app.js:7
Show 15 more frames
Show less
0 likes
0 replies

Please or to participate in this conversation.