vue-mapbox
vue-mapbox copied to clipboard
Nuxt compatibility
This module doesn't seem to be compatible with Nuxt, because of map-promisified.
This is where the error happens:
(https://raw.githubusercontent.com/soal/map-promisified/master/dist/mapPromisify.js)
If I try to patch temporarily it and refactor the dist version to a normal module without window, then the error moves to this line:
Which is this line: https://github.com/soal/map-promisified/blob/master/src/promisifyMethod.ts#L27
I am not sure if this is a incorrect use of map-promisified by vue-mapbox or a bug in map-promisified.
nuxt: v2.4.3
Nuxt have a special option for JS to be run only on client-side with ssr: false
option: https://nuxtjs.org/guide/plugins#client-side-only
I have same issue, can't add this module to nuxt. May somebody show example how to add as plugin with ssr: false? Or another way. I have done a few tries, but not solve this.
Just create a mapbox.js file in the plugins folder and initialize the components:
plugins/mapbox.js
/* eslint-disable import/no-extraneous-dependencies */
import Vue from 'vue';
import { MglMap, MglGeolocateControl } from 'vue-mapbox';
import Mapbox from 'mapbox-gl';
Vue.component('MglMap', MglMap);
Vue.component('MglGeolocateControl', MglGeolocateControl);
Vue.prototype.$mapbox = Mapbox;
nuxt.config.js
plugins: [
{ src: '~/plugins/mapbox', mode: 'client' },
],
./compnents/Map.vue
<template>
<div
class="map"
>
<no-ssr>
<MglMap
:access-token="accessToken"
:map-style="mapStyle"
:center="center"
:zoom="zoom"
@load="onMapLoaded"
>
<MglGeolocateControl ref="geolocateControl" />
</MglMap>
</no-ssr>
</div>
</template>
Thank you very much for your solution, it works.
@michisp unfortunately this doent work for me. I am getting the error message:
the page keeeps on loading forever (even tho I deactivate all privacy related browser plugins that could interfer.
@michisp unfortunately this doent work for me. I am getting the error message:
the page keeeps on loading forever (even tho I deactivate all privacy related browser plugins that could interfer.
@transfluxus It seems like you do something mapbox specific on the server-side. Which nuxt version are you using? To use mode: 'client'
in the nuxt.config.js you need nuxt >= 2.4. Else you have to use ssr: false
which is deprecated in the next major release.
I think it is 2.4.5.
The mode for the plugin is client
. In general (in the top of the nuxt.config.js it is universal
.
Thanks for the fast response. appreciate it a lot.
I have 2 other plugins, they are just defined as string:
plugins: [
'@/plugins/vuetify',
'~plugins/element-ui',
{ src: '~/plugins/mapbox', mode: 'client' },
],
@transfluxus Okay, i can't really tell you what's the problem. It could be something in your component. Don't forget that everything before the mounted lifecycle (created() for example) will also be executed on the server-side.
mmh, I created a new page just to test the map:
<template>
<div
class="map"
>
<no-ssr>
<MglMap
:access-token="accessToken"
:map-style="mapStyle"
:center="center"
:zoom="zoom"
@load="onMapLoaded"
>
<MglGeolocateControl ref="geolocateControl"/>
</MglMap>
</no-ssr>
</div>
</template>
<script>
import Mapbox from "mapbox-gl";
import {MglMap} from "vue-mapbox";
export default {
name: "Map",
components: {
MglMap
},
data() {
return {
accessToken: "sk.eyJ1IjoicmFtaW4taWN0YSIsImEiOiJjanR6czVzYnUwazcyNDRtZ3htdmRla2x2In0.Gbsf8uPdWVWfTudW_vzhGA", // your access token. Needed if you using Mapbox maps
mapStyle: 'mapbox://styles/mapbox/streets-v11', // your map style,
location: null
};
},
created() {
// We need to set mapbox-gl library here in order to use it in template
this.mapbox = Mapbox;
}
};
</script>
haha, I can trash that token :D
@transfluxus: Should be look like this:
<template>
<div
class="map"
>
<no-ssr>
<MglMap
:access-token="accessToken"
:map-style="mapStyle"
:center="center"
:zoom="zoom"
@load="onMapLoaded"
>
<MglGeolocateControl ref="geolocateControl"/>
</MglMap>
</no-ssr>
</div>
</template>
<script>
export default {
name: "Map",
data() {
return {
accessToken: "test", // your access token. Needed if you using Mapbox maps
mapStyle: 'mapbox://styles/mapbox/streets-v11', // your map style,
location: null
};
},
};
</script>
You don't have to import mapbox and mapbox-vue because it's also done inside the nuxt.config.js. Just define your components like I did it in the ~/plugins/mapbox.js
I see the world! climate change research thanks you 1000 times!
Hi, after getting it to work I wanted to start displaying data on the map. But however, besides the loaded style I cannot add anything to the map.
I see the Controls in the dom, but not in the Vue component tree (in the dev-addon). e.g.
<MglNavigationControl ref="navigationControl" position="bottom-right" />
<MglGeolocateControl/>
<MglPopup :coordinates="popupCoordinates">
<span>Hello world!</span>
</MglPopup>
no iead what ref means...
also I have to add all components in the plugin file:
import { MglMap, MglGeolocateControl, MglNavigationControl, MglPopup } from 'vue-mapbox';
import Mapbox from 'mapbox-gl';
Vue.component('MglMap', MglMap);
Vue.component('MglGeolocateControl', MglGeolocateControl);
...
If I import and add them to my map component/page the page wont load with window not defined error message.
ok, so the css import was missing, which can also be included in the page:
head() {
return {
link: [{
href: "https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css",
rel: "stylesheet"
}]
}
},
@transfluxus You dont have to import it like that.
Just add a style-tag with the src. If you do it like this nuxt takes the css from your node-modules
<style src="mapbox-gl/dist/mapbox-gl.css"></style>
<style lang="scss" scoped>
.spot__map {
margin: 0 20px;
width: auto;
.mgl-map-wrapper {
position: absolute;
}
}
</style>
This is more of a heads up comment, but I think this is related-- I have a similar setup as this comment: https://github.com/soal/vue-mapbox/issues/94#issuecomment-476551707 and that works fine, but when I add in a Navigation Control it works until I navigate away, and then it throws "TypeError: Cannot read property 'off' of undefined" in the beforeDestroy hook. Afaik it's just the Navigation Control specifically in that stage of the lifecycle. I tried it in a project that doesn't use Nuxt and it works fine, but I also tried Geolocate Control in my Nuxt project and that works fine too. Debugger shows this._map is coming back as undefined in the onRemove function:
ko.prototype.onRemove=function(){i.remove(this._container),this.options.showCompass&&(this._map.off("rotate",this._rotateCompassArrow)
thanks @michisp after these test, I need to start bringing the map into my main app and my previous method didn't work but yours does...
except for the
@laurpaik aaarggh,, yes I get the
"TypeError: Cannot read property 'off' of undefined"
error too when I navigate away.
Somebody knows a fix?!
[edit] oh in my super minimal test app, navigation actually still works...
Also I use some vuetify icons in my layout, and they are not available anymore but are replaced by overly large text. I guess cuz I am in client mode? also not so great :/
oh well,,, blindly copy pasting my test map page-component into my main app brought the icons back and ripping out the Navigation Control (thanks @laurpaik ), which is not crucial makes it work.
aside from messed up layer style color... I think a npm install just did that...
FYI, from nuxt 3 onwards, no-ssr is going to be deprecated.
- <no-ssr> </no-ssr>
+ <client-only> </client-only>
I've got vue-mapbox working with the plugin method but I'm having trouble accessing the map directly in a component. I have a watcher watching route changes and I need to fire this.map.resize()
, but I can't figure out how to actually access this.map
. Any ideas? I've tried using this.$mapbox
that the plugin is apparently exporting, but I can seem to wrap my head around how to access it.
I've got vue-mapbox working with the plugin method but I'm having trouble accessing the map directly in a component. I have a watcher watching route changes and I need to fire
this.map.resize()
, but I can't figure out how to actually accessthis.map
. Any ideas? I've tried usingthis.$mapbox
that the plugin is apparently exporting, but I can seem to wrap my head around how to access it.
@gorbypark Use the ref attribute to access the map.
<MglMap :access-token="accessToken" :map-style="mapStyle" ref="map" ></MglMap>
Then you can access it: this.$refs.map.resize()
I've followed https://github.com/soal/vue-mapbox/issues/94#issuecomment-476551707 but I'm seeing MapBox not defined?
nuxt.config.js
plugins: [
"~plugins/vue-scrollto.js",
"~plugins/global.js",
{ src: '~/plugins/mapbox', mode: 'client' },
],
/plugins/mapbox.js
/* eslint-disable import/no-extraneous-dependencies */
import Vue from 'vue';
import { MglMap, MglGeolocateControl } from 'vue-mapbox';
import Mapbox from 'mapbox-gl';
Vue.component('MglMap', MglMap);
Vue.component('MglGeolocateControl', MglGeolocateControl);
Vue.prototype.$mapbox = Mapbox;
<template>
<div class="map">
<client-only>
<MglMap
:access-token="accessToken"
:map-style="mapStyle"
:center="location"
:zoom="zoom"
@load="onMapLoaded"
>
<MglGeolocateControl ref="geolocateControl" />
</MglMap>
</client-only>
</div>
</template>
<script>
export default {
data() {
return {
accessToken: "MYTOKEN", // your access token. Needed if you using Mapbox maps
mapStyle: "mapbox://styles/mapbox/light-v9", // your map style
location: [-111.549668, 39.014],
zoom: 13,
};
},
created() {
// We need to set mapbox-gl library here in order to use it in template
this.mapbox = Mapbox;
}
};
</script>
Appreciate any help offered
@granttransition this.mapbox = Mapbox
is the problem and it will not work like this. Mapbox is not defined. You can already access it globally with this.$mapbox, you don't have to set it.
And take care of the created hook. Code in there will run on server-side also and this.$mapbox is not defined there. With if (process.client) {}
you can run code on client-side only in beforeCreate and created hooks
For anyone else reading, I completely removed the created
statement along with @load="onMapLoaded
as this was causing errors, and I can't see what it's purpose is?
always self is not defined,,,,
Has anyone managed to get it working with Nuxt 3? I have this error:
[nuxt] [request error] HTMLElement is not defined
at $id_2d7d4933 (./.nuxt/dist/server/server.mjs:23691:20)
at __instantiateModule__ (./.nuxt/dist/server/server.mjs:31884:9)
at __ssrLoadModule__ (./.nuxt/dist/server/server.mjs:31822:25)
at ssrImport (./.nuxt/dist/server/server.mjs:31847:13)
at $id_3e3bc7b9 (./.nuxt/dist/server/server.mjs:23435:37)
at async __instantiateModule__ (./.nuxt/dist/server/server.mjs:31884:3)
.vue
<template lang="pug">
section(class="bg-grey h-[200px]")
GMapAutocomplete(placeholder="This is a placeholder" @place_changed="setPlace")
client-only
MglMap(:accessToken="ACCESS_TOKEN" :mapStyle="MAP_STYLE" :center="center_default" :zoom="zoom_deafult" :animate="true")
</template>
<script setup>
import { MglMap, MglMarker } from "vue-mapbox"
import 'mapbox-gl/dist/mapbox-gl.css'
import { ACCESS_TOKEN, MAP_STYLE } from '@/utils/mapbox-config'
defineNuxtComponent({
MglMap,
MglMarker
})
const center_default = [15.859986, 42.314909]
const zoom_deafult = 4.5
function setPlace(place) {
const lat = place.geometry.location.lat()
const long = place.geometry.location.lng()
}
</script>
I am using the vue-mapbox in nuxt, but it gives me a compatibility issue with nuxt & working fine for the vue app. I found out the correct way to use vue-map in nuxt. I hope it will be helpful for someone. .nuxt.config.js
{ src: '~/plugins/vueMapBox', mode: 'client' },
Use the registration of components here
.vueMap.js
import Vue from 'vue';
import { MglMap, MglGeolocateControl, MglMarker, MglNavigationControl, MglFullscreenControl } from 'vue-mapbox';
import Mapbox from 'mapbox-gl';
Vue.component('MglMap', MglMap);
Vue.component('MglGeolocateControl', MglGeolocateControl);
Vue.component('MglMarker', MglMarker);
Vue.component('MglNavigationControl', MglNavigationControl);
Vue.component('MglFullscreenControl', MglFullscreenControl);
Vue.prototype.$mapbox = Mapbox;
.vueFile
<template>
<div id="map" class="card map-card-h">
<div class="card-body">
<div v-if="showMap" class="h-100">
<MglMap :zoom="4" :minZoom="5" :accessToken="accessToken" :mapStyle.sync="mapStyle" :center="coordinates">
<MglMarker :coordinates="coordinates" color="blue" />
<MglNavigationControl position="top-left" />
<MglFullscreenControl />
</MglMap>
</div>
</div>
</div>
</template>
<script>
import 'mapbox-gl/dist/mapbox-gl.css'
export default {
props: {
coordinates: Array,
},
data() {
return {
showMap: true,
mapbox: null,
mapStyle: 'mapbox://styles/mapbox/streets-v11',
accessToken: <token>,
}
},
}
</script>