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
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:
the initialization of the slider is enclosed into a function
in the initialization is implemented an event handler that saves the current position of the slider in the Alpine store, also the first element to display (0 by default) is set
a custom event is sent from the backend which is intercepted using Alpine and which reinitializes the slider at the saved position, using nextTick() to allow Livewire to apply his settings first
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>