been stuck here for 2 days now, please advise.
I have this Livewire ProductDetail modal that shows when Livewire public $show = true
and I have a listener listening for a viewProduct
event and when the event is received the viewProduct
public method is called and the product is assigned to public $product
then $this->show = !this->show
and the modal is displayed as expected.
The problem is that I have a js script in the blade file that implements a zoom function on the product image when you hover with the mouse and this gets all messed up.
I have tried different approaches using Livewire events and also Alpine js but still no luck.
Livewire ProductDetail Component
<?php
namespace AppHttpLivewire;
use AppModelsProduct;
use AppUpdatable;
use LivewireComponent;
class ProductDetail extends Component
{
use Updatable;
public $show = false;
// public $product;
protected $listeners = ['viewProduct', 'cartUpdated' => '$refresh'];
public function viewProduct(Product $product)
{
$this->product = $product;
$this->show = !$this->show;
}
public function render()
{
return view('livewire.product-detail');
}
}
product-detail.blade.php
@php
$cartContent = Cart::content();
@endphp
<div wire:igone x-data="{
show: @entangle('show'),
}" x-show="show" x-cloak class="bg-black bg-opacity-50 fixed inset-0 lg:flex lg:items-center overflow-scroll z-10">
@if (isset($product))
<div class="bg-white lg:max-w-screen-md lg:min-h-0 min-h-screen mx-auto relative w-full xl:max-w-screen-lg rounded-md overflow-hidden">
<div class="lg:flex lg:gap-6 py-6 px-4">
<div class="w-1/2 flex items-center justify-center">
<x-image-zoom :image="$product->image" />
</div>
<div class="flex-1 mt-2">
<div class="flex flex-col justify-between">
<h1 class="flex-1 text-2xl mt-1 max-w-xs leading-none">
{{ $product->name }}
</h1>
<div class="flex justify-start my-4">
<x-badge class="text-xl" :product="$product" />
</div>
<div>
<p>{{ $product->unit_size }}</p>
<div class="flex items-center justify-start space-x-2 mt-3 leading-none">
<div class="font-semibold inline-flex items-baseline text-gray-700">
<span class="text-gray-500 pr-1">Ks</span>
<span class="text-2xl" x-text="getFormattedPrice('{{ $product->discount_available }}', '{{ $product->discount }}', '{{ $product->price }}')" />
</div>
<div x-show="ifDiscountAvailable('{{ $product->discount_available }}')">
<span class="line-through tracking-tight text-gray-500 font-semibold">{{ $product->formatted_price }}</span>
</div>
</div>
</div>
<p class="text-sm text-gray-600 my-8">
{{ $product->description }}
</p>
</div>
</div>
</div>
<div class="bg-gray-200 h-32 px-3 py-3">
Footer
</div>
</div>
@endif
</div>
The problem component please have a look at this and advise
<x-image-zoom :image="$product->image" />
passing the path to the image
<div>
<div
x-data="initiate()"
x-on:mouseenter="zoomImage('myimage', 'myresult')"
x-on:mouseleave="removeCreatedElements()"
class="img-zoom-container w-full h-full relative">
<img id="myimage" src="{{ asset('storage/'.$image) }}">
<div id="myresult" class="img-zoom-result"></div>
</div>
</div>
<script>
function initiate() {
return {
zoomImage(imgID, resultID) {
var img, lens, result, cx, cy;
img = document.getElementById(imgID);
result = document.getElementById(resultID);
result.setAttribute('class', 'absolute inset-0');
lens = document.createElement("DIV");
lens.setAttribute("class", "absolute border-2 border-accent w-52 h-52");
lens.setAttribute('id', 'zoomLense');
img.parentElement.insertBefore(lens, img);
cx = result.offsetWidth / lens.offsetWidth;
cy = result.offsetHeight / lens.offsetHeight;
result.style.backgroundImage = "url('" + img.src + "')";
result.style.backgroundSize = (img.width * cx) + "px " + (img.height * cy) + "px";
lens.addEventListener("mousemove", moveLens);
img.addEventListener("mousemove", moveLens);
result.addEventListener("mousemove", moveLens);
lens.addEventListener("touchmove", moveLens);
img.addEventListener("touchmove", moveLens);
result.addEventListener("touchmove", moveLens);
function moveLens(e) {
var pos, x, y;
e.preventDefault();
pos = getCursorPos(e);
x = pos.x - (lens.offsetWidth / 2);
y = pos.y - (lens.offsetHeight / 2);
if (x > img.width - lens.offsetWidth) { x = img.width - lens.offsetWidth; }
if (x < 0) { x = 0; }
if (y > img.height - lens.offsetHeight) { y = img.height - lens.offsetHeight; }
if (y < 0) { y = 0; }
/*set the position of the lens:*/
lens.style.left = x + "px";
lens.style.top = y + "px";
/*display what the lens "sees":*/
result.style.backgroundPosition = "-" + (x * cx) + "px -" + (y * cy) + "px";
}
function getCursorPos(e) {
var a, x = 0, y = 0;
e = e || window.event;
/*get the x and y positions of the image:*/
a = img.getBoundingClientRect();
/*calculate the cursor's x and y coordinates, relative to the image:*/
x = e.pageX - a.left;
y = e.pageY - a.top;
/*consider any page scrolling:*/
x = x - window.pageXOffset;
y = y - window.pageYOffset;
return { x: x, y: y };
}
},
removeCreatedElements() {
document.getElementById('zoomLense').remove();
document.getElementById('myresult').style.backgroundImage = 'none';
}
}
}
</script>
The above script works if I do the following in ProductDetail.php
but when products change the js gets messed up
<?php
namespace AppHttpLivewire;
use AppModelsProduct;
use AppUpdatable;
use LivewireComponent;
class ProductDetail extends Component
{
use Updatable;
public $show = false;
// public $product;
protected $listeners = ['viewProduct', 'cartUpdated' => '$refresh'];
public function viewProduct(Product $product)
{
// $this->product = $product;
$this->show = !$this->show;
}
public function render()
{
// return view('livewire.product-detail');
return view('livewire.product-detail', ['product' => Product::find(1)]);
}
}
question from:
https://stackoverflow.com/questions/65895857/having-issue-with-livewire-and-an-inline-js-script-for-zooming-image