$.goMap plugin - Get markers function - javascript

I am having trouble with the goMap plugin for jquery. I want to obtain all the markers on my map, however, when calling the getMarkers() function, it returns an empty array.
I am guessing it has something to do with scopes?
I add the markers by querying the database with an ajax call.
$("#canvas").goMap({
latitude: 44.230065,
longitude: -76.50000,
zoom: 14,
maptype: 'ROADMAP'
});
load_markers();
function load_markers(query_url) {
if (query_url == undefined) {
query_url = '/posts/get_markers';
}
$.getJSON(query_url, function(data) {
$.each(data, function(pair) {
var id = data[pair]['posts']['id'];
$.goMap.createMarker({
latitude: data[pair]['posts']['lat'],
longitude: data[pair]['posts']['lng'],
draggable: false,
id: id,
html: {
ajax: "posts/ajax_show/"+id,
content: 'loading...',
popup: false
}
});
});
});
}
console.log(($.goMap.getMarkers()));
Thanks!

Try to print it in the success handler of the getJSON call, otherwise you donĀ“t know if you got the data yet. More a timing issue than scope if im correct.
$.getJSON(query_url, function(data) {
$.each(data, function(pair) {
var id = data[pair]['posts']['id'];
$.goMap.createMarker({
latitude: data[pair]['posts']['lat'],
longitude: data[pair]['posts']['lng'],
draggable: false,
id: id,
html: {
ajax: "posts/ajax_show/"+id,
content: 'loading...',
popup: false
}
});
});
console.log(($.goMap.getMarkers()));
});

Related

Using google map in Vue / Laravel

Trying to implement google map into Vue component. But having a hard time. Actually, there is no error. But no map also :) Okay, what I tried so far down below.
In laravel blade I set my api.
<script async defer src="https://maps.googleapis.com/maps/api/js?key={{env('GOOGLE_MAPS_API')}}&callback=initMap"></script>
Then in Vue component;
data() {
return {
mapName: "map",
//some other codes
}
},
mounted() {
this.fetchEstates();
},
methods: {
fetchEstates(page = 1) {
axios.get('/ajax', {
params: {
page
}}).then((response) => {
// console.log(response);
this.estates = response.data.data;
//some other codes....
//some other codes....
},
computed: {
//some other functions in computed...
//
initMap: function(){
var options =
{
zoom : 6,
center : {
lat:34.652500,
lng:135.506302
}
};
var map = new google.maps.Map(document.getElementById(this.mapName), options);
var marker = new google.maps.Marker({
map: map,
icon: 'imgs/marker.png',
url: "/pages/estates.id",
label: {
text: this.estates.price,
color: "#fff",
},
position: {
lat: this.estates.lat,
lng: this.estates.lng
}
});
google.maps.event.addListener(marker, 'click', function () {
window.location.href = this.url;
});
}
<div id="map"></div>
and last marker url id bind is in controller like this,
public function details($id)
{
$estates = allestates::where('id', $id)->first();
return view('pages.details', compact('estates'));
}
Do I missing something in Vue js? Thank you!
From our discussion in the comments, I realise that your issue is because this.estates is still not defined when initMap() is executed. Remember that you are using an asynchronous operation (via axios) to populate this.estates, so it is undefined at runtime. What you can do is:
Keep the map initialisation logic in initMap()
Move all the Google Map marker creation until after the axios promise has been resolved. You can abstract all that into another method, e.g. insertMarkers()
Also, remember that you need to define estates in the app/component data, otherwise it will not be reactive.
Here is an example:
data() {
return {
mapName: "map",
// Create the estate object first, otherwise it will not be reactive
estates: {}
}
},
mounted() {
this.fetchEstates();
this.initMap();
},
methods: {
fetchEstates: function(page = 1) {
axios.get('/ajax', {
params: {
page
}}).then((response) => {
this.estates = response.data.data;
// Once estates have been populated, we can insert markers
this.insertMarkers();
//pagination and stuff...
});
},
// Iniitialize map without creating markers
initMap: function(){
var mapOptions =
{
zoom : 6,
center : {
lat:34.652500,
lng:135.506302
}
};
var map = new google.maps.Map(document.getElementById(this.mapName), mapOptions);
},
// Helper method to insert markers
insertMarkers: function() {
var marker = new google.maps.Marker({
map: map,
icon: 'imgs/marker.png',
url: "/pages/estates.id",
label: {
text: this.estates.price,
color: "#fff",
},
position: {
lat: this.estates.lat,
lng: this.estates.lng
}
});
google.maps.event.addListener(marker, 'click', function () {
window.location.href = this.url;
});
}
},
Update: It also turns out that you have not addressed the issue of the data structure of this.estates. It appears that you are receiving an array from your endpoint instead of objects, so this.estates will return an array, and of course this.estates.lat will be undefined.
If you want to iterate through the entire array, you will have to use this.estates.forEach() to go through each individual estates while adding the marker, i.e.:
data() {
return {
mapName: "map",
// Create the estate object first, otherwise it will not be reactive
estates: {}
}
},
mounted() {
this.fetchEstates();
this.initMap();
},
methods: {
fetchEstates: function(page = 1) {
axios.get('/ajax', {
params: {
page
}}).then((response) => {
this.estates = response.data.data;
// Once estates have been populated, we can insert markers
this.insertMarkers();
//pagination and stuff...
});
},
// Iniitialize map without creating markers
initMap: function(){
var mapOptions =
{
zoom : 6,
center : {
lat:34.652500,
lng:135.506302
}
};
var map = new google.maps.Map(document.getElementById(this.mapName), mapOptions);
},
// Helper method to insert markers
insertMarkers: function() {
// Iterate through each individual estate
// Each estate will create a new marker
this.estates.forEach(estate => {
var marker = new google.maps.Marker({
map: map,
icon: 'imgs/marker.png',
url: "/pages/estates.id",
label: {
text: estate.price,
color: "#fff",
},
position: {
lat: estate.lat,
lng: estate.lng
}
});
google.maps.event.addListener(marker, 'click', function () {
window.location.href = this.url;
});
});
}
},
From what I can see in the screenshot you posted, this.estates is an array of objects? If that's the case you need to iterate through the array using forEach
this.estates.forEach((estate, index) => {
console.log(estate.lat);
//handle each estate object here
});
or use the first item in the array like so this.estates[0].lat, if you're only interested in the first item.

Angular Google Maps map click event works once

I've been having a problem very similar to this
However that persons question was never answered and my situation is subtly different.
I'm trying to add a click event to my map that will change the center of the map to the location of the click. My code to do this works great, but it only works once and then when I click again I get this error:
angular-google-maps.js:6815 Uncaught TypeError: Cannot read property 'click' of undefined
Here is my map object:
vm.map = {
center: {
latitude: l.latitude,
longitude: l.longitude
},
zoom: 13,
events: {
click: function(map, event, coords) {
vm.map = {
center: {
latitude: coords[0].latLng.lat(),
longitude: coords[0].latLng.lng()
},
};
$scope.apply();
}
}
};
And here's my html:
<ui-gmap-google-map center="location.map.center" zoom="location.map.zoom" draggable="true" options="tabLocations.map.options" events=location.map.events>
<ui-gmap-search-box template="'scripts/components/tab-locations/searchbox.tpl.html'" events="location.map.searchbox.events" parentdiv="'searchbox-container'"></ui-gmap-search-box>
<ui-gmap-marker ng-if="location.active" idKey="1" coords="location" options="{draggable: false, icon: 'images/icons/gps-marker-active.svg'}"></ui-gmap-marker>
<ui-gmap-marker ng-if="!location.active" idKey="1" coords="location" options="{draggable: false, icon: 'images/icons/gps-marker-inactive.svg'}"></ui-gmap-marker>
</ui-gmap-google-map>
After your first click you are redefining a brand new map with no click event:
vm.map = {
center: {
latitude: coords[0].latLng.lat(),
longitude: coords[0].latLng.lng()
},
};
This is overriding all the previous properties you had set before, which includes click.
Use setCenter instead:
click: function(map, event, coords) {
var latLng = new google.maps.LatLng(latitude: coords[0].latLng.lat(), latitude: coords[0].latLng.lng());
vm.map.setCenter(latLng);
}
Reference: Google Maps API

How to make dynamic markers in google maps with jSON?

I am trying to create dynamic markers to load information from my json file. For some reason, the json data never loads. When I try to load one marker, it works fine without the json data. I don't see what the error is. In the console, it says "TypeError: (intermediate value).error is not a function". Here is the code below.
html script link
<script src="https://maps.googleapis.com/maps/api/js?CLIENT ID HERE
&v=3.21&callback=initMap"
async defer></script>
External JS
var map;
function initMap() {
var myLatlng = {
lat: -25.363,
lng: 131.044
};
var centerZone = {
lat: 0,
lng: 0
};
map = new google.maps.Map(document.getElementById('map'), {
center: centerZone,
zoom: 3,
minZoom: 3
});
$.getJSON('data/data.json', function(data) {
$.each(data.markers, function(i, value) {
var myLatlng = new google.maps.LatLng(value.lat, value.lon);
alert(myLatlng);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: value.lon
});
});
}.error(function(words) {
alert(words);
}));
var secretMessages = ['This', 'is', 'the', 'secret', 'message'];
/*marker.addListener('click', function() {
map.setZoom(6);
map.setCenter(marker.getPosition());
attachSecretMessage(marker, secretMessages[0]);
});*/
function attachSecretMessage(marker, secretMessage) {
var infowindow = new google.maps.InfoWindow({
content: secretMessage
});
marker.addListener('click', function() {
infowindow.open(marker.get('map'), marker);
});
}
// google.maps.event.addDomListener(window, 'load', initMap);
}
json data
{
"markers": [
{
"id": "1",
"name": "Mesoamerica",
"lat": "-25.363",
"lon": "131.044",
"zoomLevel": "6"
}
]
}
The json data will have more objects inside, this is just a sample of how I want it.
You need to wait until the JSON data loads before doing anything with it. I suggest placing everything that relies on the JSON file in a $.done() function, like this:
$.getJSON('data/data.json').done(function(data){
//everything else
});
Your browser will continue with the other lines of code while it's waiting for the $.getJSON function to return the data. That's why you're getting the "not a function" error; you're trying to call a function on something that doesn't exist and JS doesn't know what to do with it. If you place everything in $.done(), those lines won't execute until the JSON data has successfully been retrieved.

an array of ArrayControllers

I'm doing something wrong here, but can't figure out what. I'm new to both Ember and Javascript in general, so feel free to point out any mistakes. I would appreciate an additional pair of eyes.
I basically have a google map with multiple datasets. In the controller that goes with the view I get the datasets and create an dataSetController(ArrayController) for each dataset. I then let the dataSetController load the data and add it to it's content, and an additional marker array.
When the process is done however, both dataSetControllers contain all points, instead of just the points for the particular dataset.
Below is the controller that goes with the view:
App.MapviewShowController = Ember.ObjectController.extend({
dataSets: [],
createDataSets: function() {
'use strict';
var self = this;
// clean previous data
this.get('dataSets').length = 0;
$.ajax({
url: '/active_data_sets.json',
type: 'GET',
data: {'project_id': this.get('id')},
success: function(data) {
data.active_data_sets.forEach(function(entry) {
// create a new controller for this dataset
var newds = App.AddressRecordController.create();
self.get('dataSets').pushObject(newds);
});
},
error: function() {
}
});
}
});
And the dataSetController itself:
App.AddressRecordController = Ember.ArrayController.extend({
content: [],
isActive: true,
dataSetId: 0,
markerColor: '',
datasetName: '',
map: null,
map_nelat: null,
map_nelng: null,
map_swlat: null,
map_swlng: null,
markerIcon: null,
markers: [],
mapBinding: 'App.MapData.map',
map_nelatBinding: 'App.MapData.ne_lat',
map_nelngBinding: 'App.MapData.ne_lng',
map_swlatBinding: 'App.MapData.sw_lat',
map_swlngBinding: 'App.MapData.sw_lng',
getAddresses: function(ne_lat, ne_lng, sw_lat, sw_lng) {
"use strict";
var self = this;
$.ajax({
url: '/address_records.json',
type: 'GET',
data: {'dataset_id': this.get('dataSetId'), 'ne_lat': ne_lat, 'ne_lng': ne_lng, 'sw_lat': sw_lat, 'sw_lng': sw_lng},
success: function(data) {
data.address_records.forEach(function(new_address) {
if (!self.findProperty('id', new_address.id)) {
// add to the content
self.content.addObject(App.AddressRecord.create(new_address));
// add the marker
var marker = new google.maps.Marker({
position: new google.maps.LatLng(new_address.lat, new_address.long),
map: self.get('map'),
animation: google.maps.Animation.DROP,
title: 'marker',
id: new_address.id
});
// add the marker for later reference
self.markers.push(marker);
}
});
},
error: function() {
}
});
},
newBounds: function() {
"use strict";
this.getAddresses(this.map_nelat, this.map_nelng, this.map_swlat, this.map_swlng);
}.observes('map_swlng'),
clean: function() {
'use strict';
// clean the objects in arracycontroller
this.forEach(function(el) {
el.destroy();
});
// clean the markers
this.markers.length = 0;
},
showMarkers: function() {
'use strict';
var self = this;
if(this.get('isActive')) {
this.markers.forEach(function(mkr) {
mkr.setMap(self.get('map'));
});
} else {
this.markers.forEach(function(mkr) {
mkr.setMap(null);
});
}
}.observes('isActive')
});
Update
AFter further debugging I found out that multiple AddressRecordControllers share nothing except the markers array. To circumvent the issue I now store the markers as content and that works fine. Still not clear about why the markers array is shared over different controllers.
I believe the create methods is more like a singleton so it either creates the object or returns a pointer to the object. So you are just adding to the same controller. you might try instead. Ember also has a Mixin thing that I am not sure how it works yet either.
var newds = App.AddressRecordController.extend();

gmap3 remove event listener

I want to remove event listener for click added by:
var events = {
click: function () {
// crazy stuff here :- )
}
};
$(where).gmap3(
{
events: events
}
);
Need something like:
$(where).gmap3().removeEventListener('click');
Didn't realize gmap3 was a wrapper library. Ill remove the duplicate comment.
Browsing through the gmaps3 documentation, I did not see anything specific to remove listeners with the libraries functions, but you can grab the marker with action: 'get' and then clear the listener.
Here is a example that a altered from the documentation. I added a name and tag property to the markers and at the end of this script I remove the mouseover listener from the marker with tag:'2'. For some reason this library is fickle and wants both the name and tag property to find the marker.
$('#test').gmap3({
action: 'init',
options: {
center: [46.578498, 2.457275],
zoom: 5
}
}, {
action: 'addMarkers',
markers: [
{
name : 'marker',
tag: '1',
lat: 48.8620722,
lng: 2.352047,
data: 'Paris !'},
{
name : 'marker',
tag: '2',
lat: 46.59433,
lng: 0.342236,
data: 'Poitiers : great city !'},
{
name : 'marker',
tag: '3',
lat: 42.704931,
lng: 2.894697,
data: 'Perpignan ! GO USAP !'}
],
marker: {
options: {
draggable: false
},
events: {
mouseover: function(marker, event, data) {
var map = $(this).gmap3('get'),
infowindow = $(this).gmap3({
action: 'get',
name: 'infowindow'
});
if (infowindow) {
infowindow.open(map, marker);
infowindow.setContent(data);
} else {
$(this).gmap3({
action: 'addinfowindow',
anchor: marker,
options: {
content: data
}
});
}
},
mouseout: function() {
var infowindow = $(this).gmap3({
action: 'get',
name: 'infowindow'
});
if (infowindow) {
infowindow.close();
}
}
}
}
});
//get the marker by name and tag
var mark = $('#test').gmap3({
action: 'get',
name:'marker',
tag: '2'
});
//remove the event listener
google.maps.event.clearListeners(mark, 'mouseover');
Here is an example of this script working: http://jsfiddle.net/5GcP7/. The marker in the middle will not open an infowindow when moused over.
I solved this problem in different way:
var events = {
click: function () {
if (P.settings.mapPinActive === false) {
return;
}
// crazy stuff here :- )
}
};
Instead of detaching and attaching events, global properties in settings object.

Categories

Resources