putyourlightson / craft-sprig

A reactive Twig component framework for Craft CMS.
https://putyourlightson.com/plugins/sprig
MIT License
129 stars 9 forks source link

Trouble with javascript map on a Sprig request #378

Closed shifuma closed 5 months ago

shifuma commented 5 months ago

Support Request

I have a Sprig component where you can switch between views -- one of which is a map, using Leaflet.js:

{% set selectedView = selectedView ?? 'list' %}

<button sprig s-val:selectedView="list" s-replace="#swapThis">List View</button>
<button sprig s-val:selectedView="map" s-replace="#swapThis">Map View</button>

<div id="swapThis">
  {% if selectedView == 'list' %}
    List View
  {% endif %}

  {% if selectedView == 'map' %}
    {% css "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" %}
    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
    <script>
      var map = L.map('map').setView([51.505, -0.09], 13);
      L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
    </script>
    <div id="map" style="height:500px"></div>
  {% endif %}
</div>

This works fine is map is the default view (therefore, the first sprig request). However, if my other view is the first one loaded, and I switch to the map view, the map doesn't load. It obviously feels like an order problem...but I'm not sure how to correct it. Per the docs, I've tried various htmx events (most of the after~ ones) but no luck so far.

Do you have any thoughts on what I could try?

Plugin Version

3.0.2

bencroker commented 5 months ago

As per the docs at https://putyourlightson.com/plugins/sprig#s-val :

Since HTML attributes are case-insensitive, the name should always be lower-case and in kebab-case.

So you should be using s-val:selected-view="...". Does that solve it for you?

shifuma commented 5 months ago

Ah, that was probably just my attempts to simplify the code. Confirmed that doesn't make a difference here.

Some more things I found: If I load the list view, then switch to the map view I get this error in the console: Can't find variable: L. Checking the Network tab, everything looks to be coming back in the request as I'd expect. Map doesn't show.

Based on that, it seems like it's not loading the <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> properly before the var map = L.map('map').setView([51.505, -0.09], 13); part. Even though it seems like it should be based on the order in my code?


If I load the map view first, strangely I get Error: Map container not found. but the map loads and shows properly, inside <div id="map"></div> as expected.

shifuma commented 5 months ago

Ok it seems like it's just a timing thing...? Wrapping the var map part in setTimeout(function() {...}, 500) works......kind of. The map is loaded but it's broken and displays like this for some reason:

screenshot_2024_06_23 _10 48

It feels like that part might be crossing into Leaflet support territory, but is there something better I could be doing with HTMX to only load <script>var map = L.map...</script> after a couple of seconds?

shifuma commented 5 months ago

Got it working! I had to move the CSS into my base layout template -- it wasn't being loaded properly otherwise. Then I did this:

<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
  var map;
  setTimeout(function() {
    map = L.map('map').setView([51.505, -0.09], 13);
    L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
  }, 10);
</script>
<div id="map" style="height:500px"></div>