Background:
In mapbox-gl-js
, while you can remove layers and features from a map (because the references are stored), you cannot do the same with markers. Instead one has to store the reference to any added marker, otherwise one won't be able to remove them later.
var marker = new mapboxgl.Marker().addTo(map);
marker.remove();
Setup:
I have an atom where I add every marker I create, so I can later clean them.
(defonce markers (r/atom []))
(defn add-marker [map img coordinate]
(let [marker (create-marker img)]
(.setLngLat marker (clj->js coordinate))
(.addTo marker map)
(swap! markers conj marker)))
(defn clear-markers []
(doseq [m (array-seq markers)] (.remove m))
(reset! markers []))
If I call clear-markers
however, nothing happens. No error, no warning, the marker just stays in the map.
If I remove the marker right after adding (just to try it out), it works as described in the docs:
(defn test-marker [map img coordinate]
(let [marker (create-marker img)]
(.setLngLat marker (clj->js coordinate))
(.addTo marker map)
(.remove marker)))
Obviously, with this code, the marker will be removed right after adding and thus never be on the map, which is not the desired behaviour, just a test.
I also tried other approaches on how to call .remove
on the elements of the vector, the following was my very first try:
(defn clear-markers []
(map #(.remove %) markers))
I'm fairly new to Clojure(Script), so I try to understand where my mistake is.
- Is the object in my vector not the same instance maybe, so removing it, will not affect the marker on the map?
- Or do I have to do a different approach, when trying to execute sideeffected methods on objects in a vector?
- Or did I miss something else entirely?
Just a quick guess, try replacing
map
withdoseq
here:The
map
function is lazy and won't run until it has to. Since it appears you are after a side-effect to remove markers,doseq
is the right choice. It is intended for side-effects and always runs immediately. It always returnsnil
.Also, you need to deref
markers
to get a vector, then just use that indoseq
. Do not usearray-seq
since the atom stores a plain Clojure/Script vector, not a JS array.Another tip: always prefer
mapv
tomap
. It is eager and removes many timing- & lazy-related issues. Be sure to study the Clojure CheatSheet and the CLJS version.Also, beware that Reagent makes a big difference between a Clojure list vs a vector. You sometimes need to force an (eager) vector result into a
seq
with(seq ...)
or a list via(apply list ...)
. You can also use the simple ->list function to emphasize what you are doing: