vue-leaflet/Vue2Leaflet

LMap events "update:zoom", "update:center" and "update:bounds" are triggered twice

udos opened this issue · 4 comments

udos commented

apologies for this :| -> I was wondering why LMap id firing "update:zoom", "update:center" and "update:bounds" twice when changing zoom level?

you can reproduce it in this sandbox:

by looking at the console after changing zoom level:
image

note: I am using "update:bounds" to trigger data loading, so getting the data twice... of course I could introduce axios throtteling but first I wanted to find out if I can get around it...

if this is on purpose it would be great to add the reason to the docs ;) -> https://vue2-leaflet.netlify.app/components/LMap.html#events

ps: thanks for this awesome component!

mikeu commented

Hi @udos, thanks for the report and working reproduction!

The reason you're seeing the events fire twice is that after the user changes the view, the code then does as well. The user zooms in, so Leaflet emits a moveend event, which leads to the zoomUpdated handler's being called, in which you set the reactive property this.zoom to the new value, which causes Vue to update the component and Vue2Leaflet to call setZoom on the underlying Leaflet map, which triggers another moveend event, and zoomUpdated gets called again. Luckily at this point Vue detects that the "new" zoom value is the same as the old one and so doesn't re-update the component.

The simplest way around this is to not update this.zoom, this.center, and this.bounds in the handlers. Or, if you do need access to the updated values in your component, then you can add separate initial values for them and not bind the variables you're storing the current values in back to the map, something like this: https://codesandbox.io/s/blue-morning-p9i7b?file=/App.vue

udos commented

thank you @mikeu, I understand. this is due to Vue reactivity. Your alternative suggestion (thanks!) should work in my case, otherwise I have to find a workaround.

p.s.: your explanantion (and codesandbox link) would add great value to a "tip" section in https://vue2-leaflet.netlify.app/components/LMap.html#events ;)

mikeu commented

Excellent @udos , that's great to hear! And good suggestion too I think, for the documentation :)

Hi.

@DonNicoJs , @mikeu , I think this issue should be reopened as I believe it's possible to avoid this "event doubling".

As I looked into the code the problem with bounds at least seems to be about not updating component state on 'moveend' event for example, but just - kind of - passing a value over. I think that possibly, and theoretically, if lastSetBounds got set to bounds (practically this.mapObject.getBounds()) before this line

this.$emit('update:bounds', bounds);
it should work fine as there's already a code verifying if newly set bounds are the same as previously set one:
const oldBounds = this.lastSetBounds || this.mapObject.getBounds();
const boundsChanged = !oldBounds.equals(newBounds, 0); // set maxMargin to 0 - check exact equals
if (boundsChanged) {
this.fitBounds(newBounds);
this.cacheMapView(newBounds);
}
.

Please verify if I'm right.

And just by looking at the code it seems that the same issue may also apply to https://github.com/vue-leaflet/vue-leaflet as this https://github.com/vue-leaflet/vue-leaflet/blob/db34dff79cc62bc6fa51357e953e9bcf55725c94/src/components/LMap.vue#L214 and this https://github.com/vue-leaflet/vue-leaflet/blob/db34dff79cc62bc6fa51357e953e9bcf55725c94/src/components/LMap.vue#L342 methods look quite similar to me.

And, by the way, thank You for creating and maintaining this library and all!