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.
Related
What I have:enter image description here
...
google.maps.event.addListener(marker,'click',function() {
this.map.setZoom(15);
this.map.setCenter(marker.getPosition());
console.log('hello world');
this.presentAlert(); // ERROR core.js:9110 ERROR TypeError:
//this.presentAlert is not a function
});
...
What I want:enter image description here
My code expanded:
...
public addMarker(lat: number, lng: number) {
//let latLng = new google.maps.LatLng(lat, lng);
let latLng = new google.maps.LatLng(21.576, -158.271); // hiking
// spot
let marker = new google.maps.Marker({
map: this.map,
animation: google.maps.Animation.DROP,
position: latLng
});
this.markers.push(marker); // catch 'em all
google.maps.event.addListener(marker,'click',function() {
this.map.setZoom(15);
this.map.setCenter(marker.getPosition());
console.log('hello world');
this.presentAlert(); // ERROR core.js:9110 ERROR TypeError:
// this.presentAlert is not a function
});
}
presentAlert() {
this.alertCtrl.create({
header: 'Alert',
subHeader: 'Subtitle',
message: 'This is an alert message.',
buttons: ['OK']
}).then(alert=> {
alert.present();
});
}
...
I've tried a few other things but for me, intuitively, this makes most sense. Help? Please and thank you.
Use local vartiable for this
Because this changes its value based on the context it's runs.
public addMarker(lat: number, lng: number) {
...
let that = this;
google.maps.event.addListener(marker, 'click', function() {
...
that.presentAlert();
});
}
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.
I have the following lines of code that generates a map, as seen it makes use of leaflet class to render it. Which works just fine, except that I additionally require the map to open as a new pop up window, or in a new tab on clicking anywhere on the map.
Code:-
<script src="https://unpkg.com/leaflet#1.0.1/dist/leaflet.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.0/leaflet.draw.js"></script>
/* miscellaneous stuff here */
<div class="col-sm-6 col-sm-offset-4">
<leaflet class="showMap" defaults="mappingConfig.defaults" center="mappingConfig.cityCenter" markers="markers" controls="controls"></leaflet>
</div>
How should i go about achieving the same? I've not come across any relevant code examples online, which were helpful to this particular scenario
If, in the template of the modal you have a map with the same id of the map in the main view, and put in a services the map object (to share it between the controllers), you can have same objects in modal and in the view.
angular.module('mymap.services', []).factory('MapServices', function () {
var map ={
center : {
lat: 49,
lng: 34,
zoom: 8
}, defaults : {
zoomControl: false,
attributionControl: true
},
baselayers : {
xyz: {....},
markers:[....]
};
return {
getMap: function () {
return map;
},
}});
Then you can use somethings like:
$scope.$on('leafletDirectiveMarker.map.click', function (event, args) {
$scope.map.center.lat = args.model.lat;
$scope.map.center.lng = args.model.lng;
$scope.valueModal = {};
$scope.valueModal.properties = args.model.properties.properties;
//show modal
$scope.modalPopup.show();
});
Or instead to use markers into the angular-leaflet directive you can create a layer:
leafletData.getMap("map").then(function (map) {
map.invalidateSize();
//resp is the geojson
var geojson = new L.GeoJSON(resp, {
onEachFeature: function (feature, layer) {
layer.on('click', function (e) {
$scope.map.center.lat = feature.geometry.coordinates[1];
$scope.map.center.lng = feature.geometry.coordinates[0];
$scope.feature = feature;
//open a modal
$scope.openLayersModal();
});
}
});
markers.addLayer(geojson);
map.addLayer(markers);
}, function (err) {
console.log('ERROR', err.status);
});
});
While trying to use google maps in react, dealing with an issue.
First time when the google map component gets created, it works very well.
Problem:- But if I visit some other page and then again go to the same Map containing page, the map is gone. It is not created again.
Here is the component:-
var React = require('react');
var MapLocation = React.createClass({
getInitialState: function() {
return {
map : null
};
},
componentDidMount: function () {
var that = this;
if(document.readyState !== "complete") {
window.addEventListener("load", function () {
that.createMap();
})
}
else {
that.createMap();
}
},
createMap: function () {
var lng = this.props.lng,
lat = this.props.lat,
mapCanvas = this.refs.map_canvas.getDOMNode(),
mapOptions = {
center: new google.maps.LatLng(lng, lat),
zoom: 15,
draggable: false,
scrollwheel: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(mapCanvas, mapOptions);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lng, lat),
map: map,
//icon: 'http://maps.google.com/mapfiles/ms/icons/yellow-dot.png'
});
this.setState({map: map});
},
enableScroll: function() {
if(this.state.map) {
this.state.map.set('scrollwheel', true);
this.state.map.set('draggable', true);
}
},
render: function () {
var lat = this.props.lat,
lng = this.props.lng;
return (
<div className='map-location'>
<h3 className='hotel__sub-title'>
Location
</h3>
<div onClick={this.enableScroll} id="google-map" ref='map_canvas'></div>
</div>
)
}
});
module.exports = MapLocation;
According to react documentation:
void componentDidMount()
Invoked once, only on the client (not on the server), immediately after the initial rendering occurs.
It means that after opening other pages and returning to map page again componentDidMount will not be invoked.
I suggest you to use some google maps react modules:
https://github.com/pieterv/react-googlemaps
https://github.com/tomchentw/react-google-maps
Good luck!
I am trying to asynchonios loading maps to my already rendered map:
handler = Gmaps.build('Google');
handler.buildMap({ provider: {
mapTypeId: google.maps.MapTypeId.ROADMAP,
styles: mapStyle_dark },
internal: {
id: 'map'}}, function () {
var json_array = $.getJSON("locations/async.json", function (data) {
return data;
});
var markers = handler.addMarkers(json_array);
handler.fitMapToBounds();
handler.getMap().setZoom(2);
});
My ajax response looks like this:
[{"lat":48.21042800000001,"lng":16.3822238,"infowindow":{"id":"53a0a0012d289ec127000020","image":"veq3r13nbgn5qg9c7zqk","name":"Blended Shisha Lounge Bar","categories":[{"name":"Bars","slug":"bars","icon":"bars"}],"coordinates":[16.3822238,48.21042800000001]},"picture":{"anchor":[17,17],"url":"/assets/map/icons/categories/bars-38.png","width":38,"height":38}}]
But the markers get not appended.
What I am doing wrong?
replace:
var json_array = $.getJSON("locations/async.json", function (data) {
return data;
});
var markers = handler.addMarkers(json_array);
with:
$.getJSON("locations/async.json", function (json_array) {
var markers = handler.addMarkers(json_array);
});