I want to use a mixin within my VUEJS module:
Module
<script>
var GoogleMaps = require('../mixins/GoogleMaps');
export default {
mixins: [GoogleMaps],
events: {
MapsApiLoaded: function(data) {
GoogleMaps.initGISMap(data);
}
},
}
</script>
Mixin
export default {
methods: {
initGISMap(selector) {
map = new google.maps.Map(selector, {
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP,
});
// Set initial Location and center map to this location
initialLocation = new google.maps.LatLng(48.184845, 11.252553);
map.setCenter(initialLocation);
// Create a searchmarker
searchMarker = createMarker();
// Init Autocomplete for GIS
initAutoComplete();
}
}
}
But I get an error, that GoogleMaps.initGISMap is not a function. How do I use a method of a mixin within a component?
-- edit to correct mistake I made in interpreting your needs
When using mixins, you don't reference the methods MixinName.method() - it's just 'this' - those methods and properties returned by your mixin and are first order, so to speak, so they are bound to 'this'.
<script>
var GoogleMaps = require('../mixins/GoogleMaps');
export default {
mixins: [GoogleMaps],
events: {
MapsApiLoaded: function(data) {
this.initGISMap(data);
}
},
}
</script>
Related
I'm working my first Svelte app which includes an embedded Google Map.
Setup Google Maps With Svelte 3 provided a good starting point for creating a component which asynchronously loads a Google Map. However, I can't figure out how to access the map object outside the initial onMount call, and without access to that object I can't add in functionality I want (for example, re-centering the map based on a button the user clicks).
main.js
import App from './App.svelte';
const app = new App({
target: document.body,
props: {
ready: false,
}
});
window.initMap = function ready() {
app.$set({ ready: true });
}
export default app;
App.svelte
<script>
import Map from './Map.svelte';
export let ready;
</script>
<svelte:head>
<script defer async src="https://maps.googleapis.com/maps/api/js?key={}&callback=initMap"></script>
</svelte:head>
{ #if ready }
<Map></Map>
{ /if }
Map.svelte
<script>
// Imports
import { onMount } from 'svelte';
// Globals
let map;
let container;
// Load the map async
onMount(async () => {
map = new google.maps.Map(container, {
zoom: 6,
center: { lat: 0, lng: 0 },
});
});
// This function has no access to the `map` variable created above!!
function recenterMap() {
map.setCenter({lat: 1, lng: 1});
}
</script>
<div class="full-screen" bind:this={container}></div>
<button on:click="{recenterMap}"></button>
Running the above gives an error for trying to invoke the setCenter call on an object that does not exist. I've searched for how other frameworks (React, Vue) might handle this, but the solutions are specific to the frameworks and are not applicable here.
Any help would be greatly appreciated!
I am utilizing the Geolocation API to place a marker on a map, but ESLint is complaining that GeolocationPosition is undefined. Nevertheless, the code runs and gives me the expected result, but I want to clean my code for warnings. I am new to typescript and ESlint, so I am unsure where to go from here. Any suggestions? Code and image of warning follows.
import { Map } from 'leaflet';
import { iconLocation, setMarker } from './leafletMarker';
export function getUserPosition(callback : (position : GeolocationPosition) => void) {
function success(position : GeolocationPosition) {
callback(position);
}
function error() {
console.log('Unable to retrieve your location'); // change to alerts when Alert component is ready
}
if (!navigator.geolocation) {
console.log('Geolocation is not supported by your browser'); // change to alerts when Alert component is ready
} else {
navigator.geolocation.getCurrentPosition(success, error, { enableHighAccuracy: true });
}
}
export function handleMyPosition(map: Map) {
getUserPosition((userPosition: GeolocationPosition) => {
if (map) {
const { latitude, longitude } = userPosition.coords;
setMarker(map, latitude, longitude, { icon: iconLocation });
map?.setView([latitude, longitude], 9);
}
});
}
Don't use no-undef in TypeScript projects. Just disable the rule in your config, TypeScript does the same but better.
I am tring to use the Google Map Javascript API into my VueJs project WITHOUT using this package https://www.npmjs.com/package/vue2-google-maps (because it's too limited as I see it).
So here what I have done, after having register my Vue component in app.js:
require('./bootstrap');
window.Vue = require('vue');
const app = new Vue({
el: '#app',
});
Vue.component(
'map-component',
require('./components/MapComponent.vue').default
);
In MapComponent.vue
<template>
<div id="map"></div>
</template>
<script>
export default {
data: function() {
return {
}
},
created() {
let googleApi = document.createElement('script');
googleApi.setAttribute('src', 'https://maps.googleapis.com/maps/api/js?key=AIzaSyA.......S-3SvLw_-twW72Zg&callback='+this.initMap+'');
document.head.appendChild(googleApi);
},
mounted() {
initMap: function() {
var map;
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -34.397, lng: 150.644},
zoom: 8
});
}
},
}
</script>
I also tried to switch created() with mounted(), but it shows the same error
The result without error should show a Google map on the page.
Thanks for your help
Aymeric
Try this in Created this.initMap() = function() { ... }
Your code will not work because you are trying to access a variable that is not initialized yet. In Vue First created method is executed then mounted method.
More info here: https://v2.vuejs.org/v2/guide/instance.html#Instance-Lifecycle-Hooks
I am trying to use marker-animate-unobtrusive but I keep getting this error:
I found another post on SO that talked about requiring the file after google has loaded but I do not know how to do that. in my component I have this:
import SlidingMarker from 'marker-animate-unobtrusive'
In my mounted method I have this:
SlidingMarker.initializeGlobally()
Any help is greatly appreciated
This is expected error since SlidingMarker extends google.maps.Marker class, GoogleMaps JavaScript API library needs to be loaded first, one option would to add a reference via index.html file:
<script src="https://maps.googleapis.com/maps/api/js?key=--KEY-GOES-HERE--"></script>
Another option would to utilize async JavaScript loader, e.g. scriptjs. The example for loading GoogleMaps JavaScript API and marker-animate-unobtrusive module could look like this:
created: function(){
get("https://maps.googleapis.com/maps/api/js?key=", () => {
const SlidingMarker = require('marker-animate-unobtrusive')
SlidingMarker.initializeGlobally()
const map = new google.maps.Map(document.getElementById('map'), this.mapOptions);
const marker = new SlidingMarker({
position: this.mapOptions.center,
map: map,
title: 'Im sliding marker'
});
});
}
Here is a demo for your reference
Update
With vue-google-maps library marker-animate-unobtrusive plugin could be integrated like this:
<template>
<div>
<GmapMap :center="center" :zoom="zoom" ref="mapRef"></GmapMap>
</div>
</template>
<script>
/* global google */
export default {
data() {
return {
zoom: 12,
center: { lat: 51.5287718, lng: -0.2416804 },
};
},
mounted: function() {
this.$refs.mapRef.$mapPromise.then(() => {
this.initSlidingMarker(this.$refs.mapRef.$mapObject)
})
},
methods: {
initSlidingMarker(map){
const SlidingMarker = require('marker-animate-unobtrusive')
SlidingMarker.initializeGlobally()
const marker = new SlidingMarker({
position: map.getCenter(),
map: map,
title: 'Im sliding marker'
});
google.maps.event.addListener(map, 'click', (event) => {
marker.setDuration(1000);
marker.setEasing('linear');
marker.setPosition(event.latLng);
});
}
}
}
</script>
<style>
.vue-map-container {
height: 640px;
}
</style>
Install the package google from npm this should fix it.
For my Angular Project, I generated a geolocation component and want to repeat a function findMe() to show the current location.
Part of code in the component.ts is given as below.
...
export class GeolocationComponent implements OnInit{
#ViewChild('gmap') gmapElement: any;
map: google.maps.Map;
isTracking = false;
marker: google.maps.Marker;
constructor(public globalvar: GlobalvarService) { }
ngOnInit() {
var mapProp = {
center: new google.maps.LatLng(-27.542211, 153.1226333),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map(this.gmapElement.nativeElement, mapProp);
setInterval(this.findMe(), 3000);
}
findMe() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
this.showPosition(position);
console.log("find me");
});
} else {
alert("Geolocation is not supported by this browser.");
}
}
showPosition(position) {
this.globalvar.latitude = position.coords.latitude;
this.globalvar.longitude = position.coords.longitude;
let location = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
this.map.panTo(location);
if (!this.marker) {
this.marker = new google.maps.Marker({
position: location,
map: this.map,
title: 'Got you!'
});
}
else {
this.marker.setPosition(location);
}
}
...
In
ngOnInit(),
I use
setInterval(this.findMe(), 3000);
By checking the log, I see the findMe() is only called once, but not be repeated as that I expect.
I also tried changing findMe() ==> findMe
setInterval(this.findMe, 3000);
this time, the log repeatedly appears, however there is always a error:
ERROR TypeError: _this.showPosition is not a function
Could you please help how can I repeatedly calling findMe() and why the error happens?
The correct way to invoke the interval is with the function declaration setInterval(this.findMe, 3000);. As you noted, if you include the () it is only executed once.
One of the issues that comes up with setInterval is that it changes the this context of the executing function. To fix this, you need to force it to be constant.
constructor(public globalvar: GlobalvarService) {
this.findMe = this.findMe.bind(this);
}
Additional info:
Documentation
StackOverflow Question
You can just use an arrow function that preserves this context :
setInterval(() => this.findMe(), 3000);
You can use arrow function syntax to make it work.
ngOnInit() {
setInterval(() => {
this.findMe()
}, 4000);
}
findMe = () => {
console.log('found');
}
Arrow function is referencing this as Component at all times.
Example - https://stackblitz.com/edit/angular-wkv2he
Try
setInterval(() => {
this.findMe()
}, 3000);
But I think than better solution is to use Observable interval.
interval(3000).subscribe(res => {
this.findMe()
})
Or in older versions of Angular :)
Observable.interval(3000).subscribe(res => {
this.findMe()
})