vue-leaflet/Vue2Leaflet

I want to openPopup behind search marker

maneewihok opened this issue · 14 comments

<div v-for="marker in referOjectOptions" :key="marker.id">
            <l-marker :lat-lng="[marker.lat, marker.lon]">
              <l-popup>
                {{ marker.projectNameTH }}
              </l-popup>
            </l-marker>
          </div>
methods: {
    search(event) {
      const item = this.referOjectInput;
      if (!item.lat && !item.log) {
        return;
      }
      this.$refs.leafmap.mapObject.flyToBounds([[item.lat, item.lon]]);
      // popup[item]Open ?
    },
mikeu commented

@maneewihok is there a reason you have that div around each marker? If you instead had

<l-marker v-for="marker in referOjectOptions" :key="marker.id" ref="mapMarkers">
  <l-popup>
    {{ marker.projectNameTH }}
  </l-popup>
</l-marker>

then I think you should be able to use something along the lines of this.$refs.mapMarkers[index].openPopup(), where you just have to map the item you already have to the correct index value for it.

@mikeu i try

for (let index = 0; index < item.length; index++) {
        this.$refs.mapMarkers[index].openPopup();
}

it's not work.

mikeu commented

@maneewihok sorry, I forgot to include that you have to reference the Leaflet object to open the popup on. Does it work with this.$refs.mapMarkers[index].mapObject.openPopup()?

@mikeu It doesn't open T^T

<l-map ref="leafmap" v-if="showMap" :zoom="zoom" :center="center">
          <v-tilelayer :url="url" :attribution="attribution"></v-tilelayer>
          <v-marker-cluster v-if="geoJsonLoaded" :options="clusterOptions">
            <l-marker
              ref="mapMarkers"
              :lat-lng="[markers.lat, markers.lon]"
              v-for="markers in referObjectOptions"
              :key="markers.id"
            >
              <l-popup>
                {{ markers.projectNameTH }}
              </l-popup>
              <l-tooltip>
                {{ markers.projectNameTH }}
              </l-tooltip>
            </l-marker>
          </v-marker-cluster>
        </l-map>
 methods: {
    search(event) {
      const item = this.referObjectInput;
      if (!item.lat && !item.log) {
        return;
      }
      this.$refs.leafmap.mapObject.flyToBounds([[item.lat, item.lon]]);
      this.openPopups();
    },
    openPopups() {
      const item = this.referObjectInput;
      for (let index = 0; index < item.length; index++) {
        this.$refs.mapMarkers[index].mapObject.openPopup();
        // this.$refs.mapMarkers[index].mapObject.openPopup();
      }
    },
mikeu commented

@maneewihok why are you opening every popup on the map in turn? By default, when one popup is opened, Leaflet closes every other popup so that there is only ever one shown at a time. If the last one in your array is not the one you zoomed to, then maybe the popup is opening, but only a different one not in the current view ends up being visible...?

mikeu commented

@maneewihok sorry, I am still not clear why you are opening every popup on the map each time the search method is called. That example only shows a single popup at a time, for only the one search result selected.

Perhaps you want to do something like add :id="`marker-${markers.id}`" to your l-marker, and then find the appropriate element and open it:

openPopup() {
  const item = this.referObjectInput;
  const markerToOpen = this.$refs.mapMarkers.find(m => m.$el.id === `marker-${item.id}`);
  if (markerToOpen) {
    markerToOpen.mapObject.openPopup();
  }
}

Note that this is untested code, and as I don't have any indication of how your referObjectInput object or the elements in your referObjectOptions array are structured, there might be a better approach overall. But based on what you've shown me, I think something like this should at least work.

Either way, I do not think that this represents any bug or problem with the vue2-leaflet library so I'll close the issue at this point.

mikeu commented

And @maneewihok , if you still can't get this working then I'm happy to try to help you find a solution, even with the issue closed. Hopefully you are nearly there though!

@mikeu Thank you, but the default popup is off.
Thanks for source code
Now, when it zooms to the marker You'll need to press the search button again before the pop-up will open.
What do i have to do

<l-marker
              ref="mapMarkers"
              :id="`marker-${markers.id}`"
              :lat-lng="[markers.lat, markers.lon]"
              v-for="markers in referObjectOptions"
              :key="markers.id"
            >
<l-popup>
                {{ markers.projectNameTH }}
              </l-popup>
methods: {
    search(event) {
      const item = this.referObjectInput;
      const markerToOpen = this.$refs.mapMarkers.find(
        m => m.$el.id === `marker-${item.id}`
      );
      if (!item.lat && !item.log) {
        return;
      }
      this.$refs.leafmap.mapObject.flyToBounds([[item.lat, item.lon]]);
      markerToOpen.mapObject.openPopup();

https://drive.google.com/file/d/1F1y7GX39qxcvHLmbS09T4mhf-aX-vPix/view?usp=sharing

mikeu commented

@maneewihok I watched that video, I see what you mean about having to click again. I can't see anything in the portion of your code you've shared that might explain that though. It could be all sorts of things, such as if this.referObjectInput is somehow not set correctly after the first click.

Here is a codesandbox demo that shows a simple version of what I think you are trying to accomplish, working correctly for me: https://codesandbox.io/s/marker-array-popup-0lkue?file=/src/App.vue

I hope that helps. Perhaps if you are still having trouble, you can create a demo yourself that reproduces the error. At this point, I suspect that you have a bug somewhere else in your application, but it is very hard to debug or guess at the cause without knowing what the code is doing.

Mr. @mikeu i have 1 more question
Now you can zoom in and open the popup.
But if <v-marker-cluster> is inserted when zooming, the pop-up will not appear Need to press repeatedly. Why?

          <v-marker-cluster>
            <l-marker
              ref="mapMarkers"
              v-for="obj in referenceObjects"
              :key="obj.id"
              :id="`mark-${obj.id}`"
              :lat-lng="[obj.lat, obj.lon]"
            >
              <l-popup>{{ obj.projectNameTH }}</l-popup>
            </l-marker>
          </v-marker-cluster>
search(event) {
      const item = this.selectedObject;
      if (!item || !item.lat || !item.lon) {
        return;
      }

      this.$refs.map.mapObject.flyToBounds([[item.lat, item.lon]]);
      const markerToOpen = this.$refs.mapMarkers.find(m => {
        return m.$el.id === `mark-${item.id}`;
      });
      markerToOpen.mapObject.openPopup();
    },

If there is no cluster, the pop-up is normally open.

mikeu commented

@maneewihok I believe the problem is that when the search is performed, the marker that you want to open the popup on is hidden inside a cluster. So trying to open the popup for it at that moment does nothing, because it is not visible.

To get around this, you can store the map marker object when it is found in the search method, and then respond to the @zoomend event on the map to open it then. There is one final trick too, that the marker doesn't actually appear until just after the zoom event has been fired, so you actually have to show the popup in the next Vue tick.

Here's a working example, with the changes outlined below: https://codesandbox.io/s/marker-array-popup-cluster-0lkue?file=/src/App.vue

<l-map @zoomend="showZoomedPopup" ...>
methods: {
  search() {
    // ...
    const markerToOpen = this.$refs.mapMarkers.find(...);
    this.zoomMarker = markerToOpen.mapObject; // <--- CHANGED: Save reference to map object
  },
  showZoomedPopup() {
    // If there is a saved map object after the zoom finishes, open its popup and unset it on the next tick
    if (this.zoomMarker) {
      this.$nextTick(() => {
        this.zoomMarker.openPopup();
        this.zoomMarker = undefined;
      });
    }
  }
}

Because the marker is invisible on the map until the zoom has finished, I am not sure if there is any way to open it earlier while the animation is happening. For that I think you would have to ask at the vue2-leaflet-markerclust repo about how to force one marker to be shown outside of the calculated clusters.

@mikeu thank you for support <3