Pat-leaflet dynamic?

Hi!

I'm trying to make pat-leaflet dynamic, that is it shows a list of items as markers in a map but this list can dinamically change so I need to update the map. My first attempt was to remove/add marker but I don't have any way to do it because the map is not accessible from outside javascript (I think). My second attempt is to just update the data-geojson attribute and "re run" the pattern. I've found someone already did it on other patterns (see Mockup sortable pattern: how to refresh list after appending new item? - #2 by Netroxen) but the registry.scan($('body')); does nothing (I'm trying in the console and F12 browser tools).

The number of items is around 30, so there should be no much penalty on doing it.

It is done in GitHub - collective/collective.collectionfilter: Plone addon for filtering collection results so I think it is possible

Any idea? @thet @petschki @agitator

I've made a PR which implements the Ajax-geojson feature from pat-leaflet into collective.collectionfilter AJAX GeoJSON feature by petschki · Pull Request #130 · collective/collective.collectionfilter · GitHub ... but keep in mind, this is tested on Plone 5.2.x only ... collectionfilter for Plone 6 is still WIP ...

ususally you don't need to take care of updating the map yourself as it's done by collectionfilter already ... I've several productive websites, which work well with collectionfilter and pat-leaflet eg Referenze — Italiano ...

Still using 6.0a2 so it is ok.

Reading the code, the pat-leaflet read the geo-jsondata from an url and update it when an event is rised? Also I should add <div class="plone-loader"><div class="loader" /></div> to my template to get the update.

I'll try to understand how it works, thanks!

you get everything in the maps tile/portlet of collectionfilter ... try it out:

  1. add collective.collectionfilter[geolocation] to your buildout/mxdev eggs
  2. create geolocated content ( to test for eg. one event and one document -> geolocationbehavior has to be added first)
  3. create a collection which fetches the content
  4. create a filterportlet with portal_type group criteria
  5. create a map portlet
    then
  6. filter by portal_type -> map and list gets updated
  7. zoom into map to show only one item -> list and portal_type selector gets updated

and so on ... everything without coding a line ...

Really a great product! But I would like to try to do the update by myself in my product/template without adding collective.collectionfilter, just to filter the map using a custom list and updating the data-geojson attribute. What I miss is the way to tell pat-leaflet that data has changed and recreate the widget. A registry.scan() should do it but maybe I'm missing something.

ok I understand.

The behavior of registry.scan() has changed recently so that an already scanned pattern doesn't get initialized anymore (which makes sense) ... you can help yourself with something like this:

let node = document.querySelector(".pat-leaflet");
node["pattern-leaflet"].init();

or jQuery style (I think in 6.0.0a2 you have to use this one):

var $el = $(".pat-leaflet");
$el.data("pattern-leaflet").init();

The pattern code for every pattern is stored in the instance via $el.data("pattern-<name>") ... see Patterns/base.js at master · Patternslib/Patterns · GitHub

var $el = $(".pat-leaflet");
$el.data("pattern-leaflet").init();

I get:
Uncaught Error: Map container is already initialized.

I think the best way is to create another new node and scan the new node. So I tested it and... it worked!

Steps are:

  • delete old pat-leaflet node
  • create a new one with the new geojson
  • run:
require(['pat-registry'], function (registry) {
    registry.scan($('body'));
});

another option could be to use the leaflet map functions directly to add/remove the markers. As you showed me, the map is available in as:

>> var $mymap = $el.data("pattern-leaflet").map
>> $mymap.isFullscreen()
   false
>> $mymap.zoomIn() <- this has zoomed in the map from the console!

Note:
the non jquery version does not get the pattern:

let node = document.querySelector(".pat-leaflet");
node["pattern-leaflet"].init();
Uncaught TypeError: node['pattern-leaflet'] is undefined
    <anonymous> debugger eval code:1

This a reference to manage the markers on a leaflet map, if someone need it:

var $el = $(".pat-leaflet");
var $mymap = $el.data("pattern-leaflet").map
clusters = []

$mymap.eachLayer((l) => {
if( l instanceof L.MarkerCluster)
               clusters.push(l)
     })
clusters[0].getAllChildMarkers() <- get all markers for each group
(we can use  LayerGroup instead of MarkerCluster to get all the markers with clusters[0].getLayers())


$mymap.eachLayer((l) => {
if( l instanceof L.MarkerClusterGroup) <- use MarkerClusterGroup to remove markers
               clusters.push(l)
     })	 
clusters[0].getLayers()
clusters[0].removeLayer(clusters[0].getLayers()[10]) <- remove a marker and the cluster counter get updated correctly