live() deletes my cropper instance, custom field

I made a form field that incorporates Cropper.js to select part of an image and give back the coordinates to four other input form fields. This works perfectly so far, but after the very first update to the state, the Cropper instance seems to completely disappear... When removing live(), this doesn't happen, but obviously the other four form fields are no longer being updated.

Does anyone know what the issue is here? Thank you!

image 1: without live()
image 2: with live(), cropper instance dissappeared

Field:
 ImageCropper::make('coordinates')
->image(fn (CreateMapping $livewire) => Storage::disk('public')->url($livewire->getMapType()->preview))
->columnSpan(3)
->default('0, 0, 0, 0')
->afterStateUpdated(function(Set $set, string $state) 
  {
    [$x, $y, $width, $height] = explode(', ',$state);
    $set('x', $x);
    $set('y', $y);
    $set('width', $width);
    $set('height', $height);
  })
->live()


Class:
<?php

namespace App\Forms\Components;

use Filament\Forms\Components\Field;
use Filament\Forms\Get;
use Illuminate\Support\Facades\Storage;

class ImageCropper extends Field
{
    protected string $view = 'forms.components.image-cropper';

    public $image;


    public function image(string|\Closure|null $image) :static
    {
        $this->image = $image;
        return $this;
    }

    public function getImageUrl(): ?string
    {
        if($result = $this->evaluate($this->image))
        {
            return $result;
        }
        return null;
    }
}


Blade:
<x-dynamic-component :component="$getFieldWrapperView()" :field="$field">
    <div ax-load
        ax-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('image-cropper-cropperjs') }}"
        x-data="imageCropper({
        state: $wire.{{ $applyStateBindingModifiers("\$entangle('{$getStatePath()}')") }},
        })">
        <!-- Interact with the `state` property in Alpine.js -->

        <input x-ref="arrayState" class="text-black" x-model='state'/>

        <img id="image" src="{{ $getImageUrl() }}" alt="Picture">

    </div>
</x-dynamic-component>


Script:
import Cropper from 'cropperjs';

export default function imageCropper({
    state,
}) {
    let component = null;
    let cropper = null;
    let image = null;
    let canvas = null;
    let selection = null;
    return {
        state,

        init: function () {
            component = this;
            cropper = new Cropper('#image');
            canvas = cropper.getCropperCanvas();
            image = cropper.getCropperImage();
            selection = cropper.getCropperSelection();
            selection.zoomable = false;
            image.scalable = false;


            canvas.classList.add("aspect-square");

            // Function to handle Cropper.js event
            function handleSelectionChange(event) {
                component.state = selection.x + ', ' + selection.y + ', ' + selection.width + ', ' + selection.height;
            }

            selection.addEventListener('change', handleSelectionChange);

            console.log(state);
            console.log(cropper);
            console.log(canvas);
            console.log(selection);
            console.log('done!');

        },
    }
}
image.png
image.png
Solution
Okay, adding
wire:key="{{rand()}}"
to the x-dynamic-component seems to work in reinitializing the script! Now I just need to set it to the correct position 😄
Was this page helpful?