javascriptlaravellaravel-livewireswiper.js

swiper blow up when its used with livewire


I have a javascript code to make a slider, and inside the slider, there are content changes when user select deferent variation of the product, and the problem is when I try to select an variation, the slider blows up, and the javascript code won't work.

slider code:

<div class="w-full relative mt-5">
    <div class="swiper multiple-slide-carousel swiper-container relative">
        <div class="swiper-wrapper mb-16">

            @foreach ($products as $product)
                <div class="swiper-slide">
                    <div class="relative overflow-hidden rounded-lg border border-base-300 bg-base-100 shadow-2xl">
                        <a class=" mx-3 mt-3 flex h-48 overflow-hidden rounded-xl"
                            href="{{ route('Productdetail', $product->id) }}">
                            <img class="object-cover mx-auto" src=" {{ asset('upload/photos/' . $product->image_path) }} "
                                alt="product image" />

                            @if ($product->hasVariations())
                                @if (isset($selectedVariation[$product->id]))
                                    @if ($selectedVariation[$product->id]->price_sale_desacount)
                                        <span
                                            class="absolute top-0 left-0 m-2 rounded-full bg-red-500 px-2 text-center text-sm font-medium text-white">{{ intval((($selectedVariation[$product->id]->price_sale - $selectedVariation[$product->id]->price_sale_desacount) * 100) / $selectedVariation[$product->id]->price_sale) }}%
                                            داشکان </span>
                                    @endif
                                @endif
                            @else
                                @if (isset($product->price_sale_desacount))
                                    <span
                                        class="absolute top-0 left-0 m-2 rounded-full bg-red-500 px-2 text-center text-sm font-medium text-white">{{ intval((($product->price_sale - $product->price_sale_desacount) * 100) / $product->price_sale) }}%
                                        داشکان </span>
                                @endif
                            @endif



                        </a>

                        <div class=" flex flex-col justify-between mt-4 px-5 pb-16">
                            <a href="{{ route('Productdetail', $product->id) }}">
                                <h5 class="text-lg tracking-tight">{{ $product->name }}</h5>
                            </a>
                            <div class="mt-2 mb-5 flex flex-wrap items-center justify-between">

                                @if ($product->hasVariations())
                                    @if (isset($selectedVariation[$product->id]))
                                        <p class="text-center">
                                            @if ($selectedVariation[$product->id]->price_sale_desacount)
                                                <span
                                                    class="text-xl font-bold text-slate-900">{{ number_format($selectedVariation[$product->id]->price_sale_desacount) }}<span
                                                        class="text-g text-sm"> IQD</span></span>
                                                <span class="text-sm text-slate-900 line-through">
                                                    {{ number_format($selectedVariation[$product->id]->price_sale) }}</span>
                                            @else
                                                <span class="text-xl font-bold text-slate-900">
                                                    {{ number_format($selectedVariation[$product->id]->price_sale) }}<span
                                                        class="text-g text-sm"> IQD</span></span>
                                            @endif

                                        </p>
                                    @endif

                                    <select id="variation-{{ $product->id }}"
                                        wire:model="selectedVid.{{ $product->id }}"
                                        wire:change="updatePrice({{ $product->id }})"
                                        class="select select-bordered text-center mt-2 mx-auto">
                                        @foreach ($product->variations as $variation)
                                            <option value="{{ $variation->id }}">{{ $variation->size }}</option>
                                        @endforeach
                                    </select>
                                @else
                                    <p class="text-center">
                                        @if ($product->price_sale_desacount)
                                            <span
                                                class="text-xl font-bold text-slate-900">{{ number_format($product->price_sale_desacount) }}<span
                                                    class="text-g text-sm"> IQD</span></span>
                                            <span class="text-sm text-slate-900 line-through">
                                                {{ number_format($product->price_sale) }}</span>
                                        @else
                                            <span
                                                class="text-xl font-bold text-slate-900">{{ number_format($product->price_sale) }}<span
                                                    class="text-g text-sm"> IQD</span></span>
                                        @endif
                                    </p>
                                @endif

                            </div>


                            <a href="#" wire:click='addToBasket({{ $product->id }})'
                                @click="$dispatch('imtemAddedToBasket')"
                                class="flex absolute left-2/4 bottom-5 px-16 translate-x-[-50%] items-center justify-center rounded-md bg-slate-900 py-2.5 text-center text-sm font-medium text-white hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-blue-300">
                                <svg xmlns="http://www.w3.org/2000/svg" class="mr-2 h-6 w-6" fill="none"
                                    viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
                                    <path stroke-linecap="round" stroke-linejoin="round"
                                        d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z" />
                                </svg>
                                کڕین</a>
                        </div>

                    </div>
                </div>
            @endforeach


        </div>
        <div class="absolute flex justify-center items-center m-auto left-0 right-0 w-fit bottom-12">
            <button id="slider-button-left"
                class="swiper-button-prev group !p-2 flex justify-center items-center border border-solid border-indigo-600 !w-12 !h-12 transition-all duration-500 rounded-full  hover:bg-indigo-600 !-translate-x-16"
                data-carousel-prev>
                <svg class="h-5 w-5 text-indigo-600 group-hover:text-white" xmlns="http://www.w3.org/2000/svg"
                    width="16" height="16" viewBox="0 0 16 16" fill="none">
                    <path d="M10.0002 11.9999L6 7.99971L10.0025 3.99719" stroke="currentColor" stroke-width="1.6"
                        stroke-linecap="round" stroke-linejoin="round" />
                </svg>
            </button>
            <button id="slider-button-right"
                class="swiper-button-next group !p-2 flex justify-center items-center border border-solid border-indigo-600 !w-12 !h-12 transition-all duration-500 rounded-full hover:bg-indigo-600 !translate-x-16"
                data-carousel-next>
                <svg class="h-5 w-5 text-indigo-600 group-hover:text-white" xmlns="http://www.w3.org/2000/svg"
                    width="16" height="16" viewBox="0 0 16 16" fill="none">
                    <path d="M5.99984 4.00012L10 8.00029L5.99748 12.0028" stroke="currentColor" stroke-width="1.6"
                        stroke-linecap="round" stroke-linejoin="round" />
                </svg>
            </button>
        </div>
    </div>
</div>

javascript:

var swiper = new Swiper(".multiple-slide-carousel", {
        // loop: true,
        slidesPerView: 2,
        spaceBetween: 20,
        navigation: {
            nextEl: ".multiple-slide-carousel .swiper-button-next",
            prevEl: ".multiple-slide-carousel .swiper-button-prev",
        },
        breakpoints: {
            2560: { // 4K screens
                slidesPerView: 7,
                spaceBetween: 40
            },
            1920: { // Full HD screens
                slidesPerView: 6,
                spaceBetween: 40
            },
            1440: { // QHD screens
                slidesPerView: 5,
                spaceBetween: 30
            },
            1028: {
                slidesPerView: 4,
                spaceBetween: 30
            },
            768: { // Tablets
                slidesPerView: 3,
                spaceBetween: 20
            },
            576: { // Mobile devices
                slidesPerView: 2,
                spaceBetween: 10
            }
        }

    });

I tried dispatch an event when content changes, and write script code inside that event listener but it isn't fixed the problem


Solution

  • The problem is that when you call a backend method (for example using wire:change) the DOM is rewritten and therefore external javascript libraries lose their references.

    This is a possible solution:

    In the backend:

    public function updatePrice($id)
    {
        // do some stuff
    
        $this->dispatch('price-updated');
    }
    

    In the frontend:

    <div x-data="{swiper: null}"
         x-init="$store.mySwiperPosition = 0; swiper = initSwiper()"
         @price-updated.window="$nextTick(() => swiper = initSwiper($store.mySwiperPosition))"
    >
        <div class="swiper multiple-slide-carousel swiper-container relative">
    
            .....
    
        </div>
    
    </div>
    
    ......
    
    <script>
    
        function initSwiper(initialSlide = 0) {
    
            return new Swiper(".multiple-slide-carousel", {
    
                initialSlide: initialSlide, // ~~~> added
    
                slidesPerView: 2,
    
                .....
    
                on: {     // ~~~> added
    
                    activeIndexChange: function (thisSwiper) {
                        Alpine.store("mySwiperPosition", thisSwiper.activeIndex)
                    },
               }
            })
        }
    
    </script>