What is the method for accessing a map that has been set in a separate component?

My current setup involves utilizing a Leaflet map with vue2leaflet.

The process I follow is quite standard:

  • I import a list of places from a REST Api in the app store (vuex)
  • Following that, during map initialization, the markers are created using the information stored

Essentially, my Map.vue module calls the map like this:

<v-map ref="map" :zoom="zoom" :center="center">
    <v-tilelayer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"></v-tilelayer>
    <v-marker-cluster :options="clusterOptions">
        <v-marker v-for="(marker, index) in markers"
            :key="index"
            :lat-lng="makeCoords(marker.location.lat, marker.location.lng)"
                v-on:l-click="showSpot(marker._id, marker.slug, marker.location.lat, marker.location.lng)">
        </v-marker>
    </v-marker-cluster>
</v-map>

The Markers data comes from the store ($store.map.markers):

computed: {
    markers () {
        return this.$store.state.map.markers
    }
}

In the same Template, to obtain a reference to the map, do the following:

this.$refs.map

If another file, say "AddMarker.vue", needs to place new markers on the map, use this method:

L.marker([datas.location.lat, datas.location.lng]).addTo(mymap);

where "mymap" refers to the object defined in Map.vue

However, attempting to access this.$refs.map from another file results in "undefined".

Several attempts were made to add the map reference to the store but encountered errors. Storing components in this manner seems problematic.

Simply adding the new marker to the store does not automatically update the map. The addTo() method needs to be called.

Below is the store configuration:

export const state = () => ({
    markers: null
})

export const mutations = {
    setMarkers(state, markers) {
        state.markers = markers
    },

    addMarker(state, marker) {
        state.markers.push(marker)
    }
}

export const actions = {
    async init({ commit }) {
        let { data } = await this.$axios.get(process.env.api.spots)
        commit('setMarkers', data)
    }
}

To call the mutation:

    that.$store.commit('map/addMarker', {
            title: values.title,
            description: values.description,
            location: {
                city: that.$store.state.position.infos.city,
                country: that.$store.state.position.infos.country,
                lat: that.$store.state.position.coords.lat,
                lng: that.$store.state.position.coords.lng
            }
        });

Although the marker is successfully added to the store, it doesn't reflect on the map. Seeking help and advice on how to resolve this issue. Thank you!

Answer №1

Your challenge lies in how to incorporate an additional marker into the markers array. If you define markers as a computed property that is linked to the store, all you need to do is append a new marker to the store.

Vue.component('v-map', Vue2Leaflet.Map);
Vue.component('v-tilelayer', Vue2Leaflet.TileLayer);
Vue.component('v-marker', Vue2Leaflet.Marker);

const store = new Vuex.Store({
  state: {
    markers: [
      [47.42, -1.25],
      [47.41, -1.21],
      [47.43, -1.22]
    ].map(p => L.latLng(...p))
  },
  mutations: {
    addMarker(state, payload) {
      state.markers.push(payload);
    }
  },
  actions: {
    addMarker({commit}, payload) {
      commit('addMarker', payload)
    }
  }
})

const v = new Vue({
  el: '#app',
  store,
  data() {
    return {
      zoom: 13,
      center: [47.413220, -1.219482],
      url: 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
      attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
    }
  },
  computed: {
    markers() {
      return this.$store.state.markers;
    }
  }
});

setTimeout(() => {
  store.dispatch('addMarker', L.latLng(47.412, -1.24));
}, 1400);
html,
body,
#app {
  height: 100%;
  margin: 0;
}
<script src="//unpkg.com/vue@latest/dist/vue.js"></script>
<script src="//unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e18d8480878d8495a1d0cfd1cfd2">[email protected]</a>/dist/leaflet.js"></script>
<script src="//unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b7c1c2d2859adbd2d6d1dbd2c3f7879987998280">[email protected]</a>/dist/vue2-leaflet.js"></script>
<script src="//unpkg.com/vuex@latest/dist/vuex.js"></script>
<link href="//unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3c50595d5a5059487c0d120c120f">[email protected]</a>/dist/leaflet.css" rel="stylesheet" />
<div id="app">
  <v-map :zoom="zoom" :center="center">
    <v-tilelayer :url="url" :attribution="attribution"></v-tilelayer>
    <v-marker v-for="marker in markers" :lat-lng="marker"></v-marker>
  </v-map>
</div>

Answer №2

Imagine a scenario where you have various components that need to interact with each other through an event bus. For example, you have components responsible for adding markers on a map when a user clicks on a specific address from a list.

// event-bus.js
import Vue from 'vue';
export const EventBus = new Vue();

// address-list.vue
import { EventBus } from './event-bus.js';

methods: {
   onClick () {
      EventBus.$emit('add-marker', {x:123,y:345});
   }
}

// map.vue
import { EventBus } from './event-bus.js';

EventBus.$on('add-marker', coords => {
   this.addMarker(coords).then(() => this.redrawMap())
});

This setup is simple yet effective with minimal code. By using a global event bus, you can easily reuse it in any component as needed.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it permissible to use Aloha editor GPL v.2 on a business website?

While researching the licensing of Aloha Editor, I came across some confusing information. I found a reference to another editor under LGPL: However, I couldn't find a clear answer on whether I can use Aloha JS code on a commercial website with GPL v ...

Converting Node.js Date.toString() output into a time format in Go

My go service is currently receiving data from an external source. Here's how the data appears (in JSON format)- { "firstName": "XYZ", "lastName": "ABC", "createdAtTimestamp": "Mon Nov 21 2 ...

Is it feasible to activate a Bootstrap Tooltip from a different element?

I am currently developing a system that enables users to add notes over an image they upload. Presently, I have a note div that, upon clicking, opens a text box for editing. When hovering over this div, I utilize Bootstrap Tooltip to preview the contents o ...

Utilize interpolation with ES6 and an Angular 1.4 directive

Currently experimenting with the unique ES6 + Angular combination and facing a challenge in interpolating an html string within a directive that includes scope bindings. We have attempted the following approach: Current scenario The code below is functi ...

Ways to extract a specific value from a geojson object using the key name

After making a call to the back-end, I retrieved the below geojson data in the 'data' object. However, when trying to access the values of the 'type' and 'features' keys within the geojson, I encountered difficulties. data["g ...

Achieving a scrolling body with a fixed header in a Vue b-table

Currently, I have implemented a b-table element on a webpage to display data from a database. The table is paginated, but feedback suggests that users prefer all information displayed in a single scrolling view. However, the issue arises when I attempt to ...

Registration and Mapping Interface API

Recently, I have been researching information for an application that we are planning to develop for our chain of stores (approximately 20). Our goal is to reward customers with points when they check-in at our store locations. Additionally, we aim to show ...

Any suggestions on how to display the data names field in the vue-multiselect plugin on the edit page?

Currently, I am working on the edit page for employees on my vue laravel SPA. The create employees page is already set up and I am utilizing the vue-multiselect plugin () to display data. At present, I have managed to show the employee ID's from an ar ...

Can you provide an example and explain the functions `getOptionSelected` and `getOptionLabel` in Material UI?

While going through the Mui Documentation, I came across the Autocomplete component section and found two interesting props: getOptionLabel and getOptionSelected. Although I read their definitions, I'm still struggling to grasp them fully. Can someone ...

Adjusting the height of an element as you scroll will activate the scroll event

One issue I'm facing is with adding a class to my header. The goal is to reduce the height of the top part of the header when the user scrolls down and then remove the class when they scroll back up. While this functionality is working, there is an un ...

Utilizing PHP Variables in an External JavaScript: A Step-by-Step Guide

I am attempting to utilize an array generated in PHP within my external JavaScript. My PHP code retrieves images from a directory based on the user ID provided via URL and stores them in an array. I aim to use this array in JavaScript to create a photo sli ...

Opinions on crafting a new gadget?

I will only provide each website interested in my widget with the code to copy and paste once. It is crucial that the code is future-proof. After much consideration, this is the widget code I have developed: <script type="text/javascript" src="http:/ ...

Linking the location of the pop-up to the currently selected text box

I am currently experimenting with setting the top and left values relative to the selected_element (which is active at the time of triggering the popup) in a manner similar to a tooltip. I attempted to use $().position() in combination with jQuery, but it ...

What is the best way to retrieve the most recent CMS posts information within a Gatsby-constructed project?

I created a static website using Gatsby and everything was working well. However, I encountered an issue when updating the titles and content of posts in Contentful CMS - the changes were not reflected when I refreshed the website. How can I ensure that ...

Tips for correctly displaying diacritics with Webpack and Typescript

While working on my project, I encountered an issue with diacritics marks (such as German or Polish characters) when using Webpack with Typescript. Unfortunately, the problem arises when trying to display these marks in the console or on a webpage. It seem ...

Tips for changing the state of a toggle button with JavaScript

I need help creating a toggle button. To see the code I'm working on, click here. In my JavaScript code, I am reading the value of a 'checkbox'. If the value is true, I add another div with a close button. When the close button is clicked, ...

How can I apply concatMap in Angular?

Can you please guide me on how to effectively utilize concatMap with getPrices() and getDetails()? export class HistoricalPricesComponent implements OnInit, OnDestroy { private unsubscribe$ = new Subject < void > (); infoTitle ...

Creating a Set of Buttons in HTML

Need some assistance with grouped buttons. Let's consider a scenario where there are 5 buttons on an HTML page. When the 3rd button is clicked, buttons from 0 to 3 should change color and the function should return 3. Similarly, when the 5th button is ...

jQuery failing to append code after being removed

I need some assistance with an issue I've run into while using jQuery's .remove(). Here is a snippet of code that showcases the problem: $( '.video-button span.glyphicon-play' ).click(function() { $( '#video-player' ).ap ...

Adjust the width of a container to exceed 32767 using jquery in the Opera browser

I am looking to create a compact timeline using jQuery, and I want this timeline to have a width exceeding 32767 pixels. Interestingly, when I attempt to modify the width using the jQuery code $(".timelinecontainer").width(32767);, it doesn't seem to ...