Search code examples
vuejs2leaflet

Display a list in leaflet popup



I want to display an unorderd list or table in a leaflet popup. The number of items and their content are different and depend on the type of element which was clicked.
So ideally the popup content should be created on the click event.

I tried to build the list inside the bindPopup function, but it's not working.

      L.marker([mapElement.y * -1, mapElement.x], {
      uniqueID: mapElement.elementID,
      mapIconWidth: mapElement.width,
      icon: new mapIcon({
        iconUrl: icon.mapIcon.imageData,
        iconSize: [elementSize, elementSize]
      })
    })
      .addTo(markers)
      .bindPopup(mapElement.element.nbr + ' ' + mapElement.element.name +  "<br/<ul>  <li v-for='state in mapElement.element.states'>{{ state.definition.stateTypeTitle }}</li> </ul>");

That's the output:

enter image description here

Any ideas would be great! Thanks!


Edited code (get this error message: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.):

LoadMarker(mapID) {
  console.log("Load Markers");
  map.removeLayer(markers);
  markers.clearLayers();

  fetch(this.$apiUrl + "/mapelements/" + mapID)
    .then(response => response.json())
    .then(received => {
      let mapElements = received;
      let mapZoom = map.getZoom();

      mapElements.forEach(function(mapElement) {
        let elementSize = (mapElement.width / 8) * mapZoom;


          let popup = new Vue({
          template:
            mapElement.element.nbr +
            " " +
            mapElement.element.name +
            "<br/<ul>  <li v-for='state in mapElement.element.states'>{{ state.definition.stateTypeTitle }}</li> </ul>",
          data: {
            mapElement
          }
        }).$mount().$el;


        let icon = mapIconSchemas.find(
          schema => schema.mapIconSchemaID == mapElement.mapIconSchemaID
        );
        if (icon != null) {
          L.marker([mapElement.y * -1, mapElement.x], {
            uniqueID: mapElement.elementID,
            mapIconWidth: mapElement.width,
            icon: new mapIcon({
              iconUrl: icon.mapIcon.imageData,
              iconSize: [elementSize, elementSize]
            })
          })
            .addTo(markers)
            .bindPopup(popup);
        }
      });
    });

  map.addLayer(markers);
},

Solution

  • There is a solution, if you want to use the vue templating engine to fill the popup content.

    I explained it for this question.

    You create a component with the content you want to display in the popup, but you hide it :

    <my-popup-content v-show=False ref='foo'><my-popup-content>
    

    Then you can access the generated html of that component in your code like this :

    const template = this.$refs.foo.$el.innerHTML
    

    and use it to fill your popup.

    The big advantage of that method is that you can generate the popup content with all the vue functionalities (v-if, v-bind, whatever) and you don't need messy string concatenations anymore.