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

Showing undefined or null values in React and JavaScript

My goal is to format undefined or null values by italicizing them. If the value is an empty string, it should be displayed as is. If it has a value, that value should also be displayed as is. However, I am encountering an issue where null or undefined val ...

What is the best way to display just one record that has the lowest score out of all the records?

I need help with displaying only 1 record from the DL list that has the lowest score, instead of showing all records. In the example on stackblitz, you can see that for the first record, the DL scores are: 54, 20, and updated. Instead of displaying all 3 ...

Struggling to find multiline content in a SWIFT message using regex

Looking into a SWIFT message using RegEx, here is an excerpt: :16R:FIN :35B:ISIN CH0117044708 ANTEILE -DT USD- SWISSCANTO (CH) INDEX EQUITY FUND USA :16R:FIA The goal is to extract information in group 3: ISIN CH0117044708 ANTEILE -DT USD- SWISSCANTO (C ...

Support for OData in Vue and Vuetify Data Tables

I am currently working with odata-enabled endpoints and I want to connect them to data tables in vue. My goal is to have server-side sorting, filtering, and paging functionalities automatically supported. The grid in Telerik's Kendo UI makes it easy t ...

What is the reason for the filter not displaying the IFRAME?

I have a filter set up to automatically embed YouTube videos for user-generated content by searching for links and verifying if they are valid YouTube videos. If they are, the video should be embedded using standard iframe code; otherwise, it remains just ...

Is there no body sent in the $.ajax post request?

My server is returning an error when I try to make a simple post request. It's saying that the post request has no body and all the keys have an "undefined" value. Here is the code for my post request: let alert_title = 'Alert'; let alert ...

Difficulty in transmitting two boolean values using ajax and setTimeout()

I am working on two functions that are supposed to send either 0 or 1 to a PHP page using AJAX. When a key is pressed on the keyboard, the function that sends 1 should start, followed by the second function that sends 0 three seconds later using setTimeout ...

Using Typescript and webpack to detect variables that are defined in the browser but not in Node environment

My goal is to create a package that can be used on both servers and clients with minimal modifications required. Some libraries are available in Node but not in a browser, while others are accessible in a browser but not in Node. For instance, when utili ...

What is the best way to create a taskbar using HTML or Javascript?

I'm currently developing an innovative online operating system and I am in need of a functional taskbar for user convenience. The ideal taskbar would resemble the Windows taskbar, located at the bottom of the screen with various applications easily ac ...

A Guide to Importing CSV Data Into a Datatable

Is there a way to efficiently import data from a CSV file and display it in a table using the datatables plugin? Currently, I have a fixed table structure: <table id="myTable" class="table table-striped" > <thead> ...

WordPress CSS & JS files failing to enqueue properly

My attempt to integrate my CSS and JS files with WordPress has not been successful. Although my CSS works through the Custom CSS tab, this is not an ideal solution. Below is the code from my functions.php file for your reference. Can you help me troublesho ...

Implementing server-side validation measures to block unauthorized POST requests

In my web application using angular and node.js, I am in the process of incorporating a gamification feature where users earn points for various actions such as answering questions or watching videos. Currently, the method involves sending a post request t ...

What is the best way to incorporate a loop into a React return statement?

After learning React, I decided to develop the Tic-tac-toe game following the official documentation. There were extra tasks listed below the "Tutorial" section, and one of them was: "Rewrite the Board component to use two loops to generate the squares in ...

Retrieve the id of the anchor tag that was selected upon clicking, and then dynamically change the content of another div

Seeking guidance on how to dynamically change the content of a div element based on which anchor tag is clicked. Below is the HTML structure and JavaScript function I have attempted: HTML: <div> <a id="a1" href="javascript: changeDiv();">tag1 ...

Having trouble choosing multiple options from autocomplete drop-down with Selenium web-driver in Python

I am currently in the process of automating a webpage built with Angular that features an auto-complete dropdown with numerous elements. My goal is to click on each individual element and verify if it populates all the fields below accordingly. Below is th ...

Encountering an error message saying "assignment to undeclared variable"

I'm attempting to incorporate a react icon picker from material-ui-icon-picker However, I keep encountering an error stating "assignment to undeclared variable showPickedIcon" edit( { attributes, className, focus, setAttributes, setFocus, setState ...

Exploring the Fundamentals of XSS

Currently, my technology stack consists of Symfony2, Twig, and Doctrine. When it comes to securing my website, I am particularly concerned about preventing XSS attacks. However, despite taking precautions, I'm not sure what more I can do. Persisten ...

Ways to remove a

After creating an npm link within a local dependency and then deleting that dependency from my hard drive, I am now attempting to remove this npm link. I have attempted the following steps: npm rm --global dependency npm uninstall dependency npm unlink - ...

I encountered an issue stating, "The function `req.redirect` is not recognized."

Recently starting out with node development. Encountering the error below: TypeError: req.redirect is not a function at Post.create (/var/www/html/node_blog/index.js:40:7) at /var/www/html/node_blog/node_modules/mongoose/lib/utils.js:276:16 a ...

Oops! You can only have one parent element in JSX expressions

I'm working on creating a password input box, but I keep encountering an error when integrating it into my JS code. Here's the snippet of my code that includes TailwindCSS: function HomePage() { return ( <div> <p className=&q ...