Laravel photo gallery with Alpine.js – Image is not fully displayed after clicking the thumbnail

Updated: Jan 31, 2025

Laravel photo gallery with Alpine.js – Image is not fully displayed after clicking the thumbnail

To create a Laravel photo gallery with Alpine.js, you can follow the steps below:

  1. Install Laravel and Alpine.js: First, make sure you have Laravel installed on your local machine or server. Then, install Alpine.js by adding it to your app.scss or app.css file:

    @import 'alpinejs';
    

    Or, add it to your webpack.mix.js file:

    require('alpinejs');
    
  2. Create a new controller for the photo gallery: Create a new controller called PhotoGalleryController.php in the app/Http/Controllers directory:

    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    
    class PhotoGalleryController extends Controller
    {
        public function index()
        {
            $photos = ['photo1.jpg', 'photo2.jpg', 'photo3.jpg']; // Replace with your actual photo paths
            return view('photo-gallery.index', compact('photos'));
        }
    }
    
  3. Create a new view for the photo gallery: Create a new file called index.blade.php in the resources/views/photo-gallery directory:

    @extends('layouts.app')
    
    @section('content')
        <div x-data="{ currentImage: '{{ asset('images/photo1.jpg') }}' }">
            <div class="gallery">
                @foreach ($photos as $photo)
                    <img src="{{ asset($photo) }}" alt="Photo" @click="currentImage = '{{ asset($photo) }}'">
                    <div class="thumbnail">
                        <img src="{{ asset('images/thumbnail-' . pathinfo($photo, PATHINFO_FILENAME) . '.jpg')) }}" alt="Thumbnail" @click="currentImage = '{{ asset($photo) }}'">
                    </div>
                @endforeach
            </div>
            <img src="{{ currentImage }}" alt="Current Image">
        </div>
    @endsection
    

    Make sure to replace '{{ asset('images/photo1.jpg') }}' with the actual path to your first photo in the x-data attribute. Also, make sure to create a thumbnail-* image for each photo and place them in the public/images directory.

  4. Create a new route for the photo gallery: Add the following line to your routes/web.php file:

    Route::get('/photo-gallery', 'PhotoGalleryController@index')->name('photo-gallery');
    
  5. Test the photo gallery: Start your Laravel server and visit http://localhost/photo-gallery in your web browser. Click on a thumbnail to see the corresponding full-size image.

    However, you may notice that the full-size image is not fully displayed after clicking the thumbnail. This is because the image is being loaded asynchronously, and the thumbnail's click event handler is executed before the full-size image has finished loading. To fix this, you can use Alpine.js's intersectionObserver to detect when the full-size image is in the viewport and then set the currentImage variable accordingly.

  6. Update the view for the photo gallery: Update the index.blade.php file as follows:

    @extends('layouts.app')
    
    @section('content')
        <div x-data="{ currentImage: '{{ asset('images/photo1.jpg') }}' }">
            <div class="gallery">
                @foreach ($photos as $photo)
                    <img src="{{ asset($photo) }}" alt="Photo" @click="showImage(this)">
                    <div class="thumbnail">
                        <img src="{{ asset('images/thumbnail-' . pathinfo($photo, PATHINFO_FILENAME) . '.jpg')) }}" alt="Thumbnail" @click="showImage(this)">
                    </div>
                @endforeach
            </div>
            <img x-show="currentImageShown" src="{{ currentImage }}" alt="Current Image" x-on:intersection="currentImageShown = true">
        </div>
    @endsection
    
    <script>
        document.addEventListener('alpine:init', () => {
            Alpine.data('gallery', () => ({
                showImage(el) {
                    this.currentImage = el.src;
                }
            }));
        });
    </script>
    

    This updated code uses Alpine.js's intersectionObserver to show the full-size image only when it is in the viewport. The currentImageShown variable is set to true when the image is in the viewport, and the full-size image is displayed using the x-show directive.

    With these changes, the full-size image should now be fully displayed after clicking the thumbnail.