Search code examples
phplaravelleafletlaravel-livewire

Leafletjs map disappears after Livewire component refresh


I have a Livewire component and inside it there is a leaflet js map. It works fine until there is a validation error or component refresh happens. When that occurs, the map disappears from the page.

This is the code in the blade file

<div>
    <x-slot name="header">
        {{ __('Create Campaign') }}
    </x-slot>

    <div class="p-4 rounded-lg shadow-xs flex items-center justify-center">

        <div class="w-8/12">

            <x-mary-form wire:submit="save">
                <x-mary-input label="Name" wire:model="name" icon="o-user"/>

                <x-mary-textarea label="Description" wire:model="description"/>

                <x-mary-input label="Address" wire:model="address" icon="o-home"/>

                <x-mary-datetime label="Date" wire:model="date" icon="o-calendar"/>

                <x-mary-datetime label="Start Time" wire:model="startTime" icon="o-clock" type="time"/>

                <x-mary-datetime label="End Time" wire:model="endTime" icon="o-clock" type="time"/>

                <label>Location</label>
                <div class="rounded" style="height: 400px" id="map"></div>

                @error('latitude')
                <x-input-error :messages="$message" />
                @enderror

                <x-slot:actions>
                    <x-mary-button link="{{ route('campaigns.index') }}" label="Cancel"/>
                    <x-mary-button label="Save!" class="btn-primary" type="submit" spinner="save"/>
                </x-slot:actions>
            </x-mary-form>
        </div>


    </div>
</div>


@script
<script>

    const map = L.map('map', {
        center: [7.29312, 80.63410],
        zoom: 14,
        minZoom: 12,
        maxZoom: 14
    });
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {}).addTo(map);
    var marker = L.marker();

    function onMapClick(e) {
        marker.setLatLng(e.latlng).addTo(map);
        console.log(e.latlng['lat']);
        console.log(e.latlng['lng']);
        $wire.latitude = e.latlng['lat'];
        $wire.longitude = e.latlng['lng'];
    }

    map.on('click', onMapClick);
</script>
@endscript


@assets

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
      integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
      crossorigin=""/>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"
        integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
        crossorigin=""></script>

@endassets

I'm expecting the map to be visible on the form even after the component refresh.


Solution

  • Livewire rewrites the DOM and this causes some conflicts with external javascript libraries as their references to the DOM are lost

    To avoid this a possible solution is to add the wire:ignore attribute to the tag managed by the external library (LeafletJs in your case).
    I usually prefer to enclose the tag with a <div> with the wire:ignore attribute:

    <div wire:ignore>
        <div class="rounded" style="height: 400px" id="map"></div>
    </div>
    

    This way Livewire will leave that <div> intact and it can be managed by the external library