I am trying to pass php $var to Javascript in google map script. I have address table in DB. And with controller I fetch it to view and now try to pass it in Javascript and iterate it.
But having some trouble I think my code a bit corrupted. By the way I dont have lat and lng, just addresses.
function initMap(){
var options = {
zoom:8,
center:
#foreach($address as $addr){
{!! $addr->address !!}
}
#endforeach
}
var map = new google.maps.Map(document.getElementById("map"), options);
var marker = new google.maps.Marker({
position:
#foreach($address as $addr){
{!! $addr->address !!}
}
#endforeach
map:map
});
var infoWindow = new google.maps.InfoWindow({
content:'content here'
});
marker.addListener('click', function () {
infoWindow.open(map, marker);
})
}
And Map API calling
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=MY-KEY&callback=initMap"></script>
controller
public function index()
{
$address = DB::table("allestates")
->get();
return view("home", compact('address'));
}
Address column in DB:
I see a few things that could be causing the issue
Try this:
function initMap(){
var options = {
zoom:8,
center:
'{!! $address[0]->address !!}'
}
var map = new google.maps.Map(document.getElementById("map"), options);
var marker = new google.maps.Marker({
position:
#foreach($address as $addr)
'{!! $addr->address !!}'
#endforeach
map:map
});
var infoWindow = new google.maps.InfoWindow({
content:'content here'
});
marker.addListener('click', function () {
infoWindow.open(map, marker);
})
}
So first of all the #foreach (...) does not use { or }
Second you want to output any information that is not only numeric inside of quotes
Hope this helps
Related
In my project, am taking values from php database and showing as markers in google maps. I want to show service name, in each location as infowindow (Multiple service names are available for each location). I want that service name displayed in infowindow line by line in each marker location.
But when i tried to show only first service name
Following is my code, I am showing only essential codes
var markerNodes = xml.documentElement.getElementsByTagName("marker");
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < markerNodes.length; i++) {
var id = markerNodes[i].getAttribute("id");
var name = markerNodes[i].getAttribute("locationName");
// console.log(name);
var address = markerNodes[i].getAttribute("locationAddress1");
var distance = parseFloat(markerNodes[i].getAttribute("distance"));
var servicename = markerNodes[i].getAttribute("serviceName");
var latlng = new google.maps.LatLng(
parseFloat(markerNodes[i].getAttribute("locationLat")),
parseFloat(markerNodes[i].getAttribute("locationLong")));
//console.log (parseFloat(markerNodes[i].getAttribute("locationLong")));
createOption(name, distance, i);
createMarker(latlng, name, address,servicename);
bounds.extend(latlng);
From above code, i will get everything from php databse,from this servicename ,i want to show as infowindow.
Following is the code for adding infowindow
function createMarker(latlng, name, address,servicename ) {
var html = servicename;
var marker = new google.maps.Marker({
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
position: latlng,
// label: "C",
icon: {
url: "{{ asset('img/new_map.png') }}"
}
});
google.maps.event.addListener(marker, 'click', function() {
infoWindow.setContent(html);
infoWindow.open(map, marker);
});
markers.push(marker);
}
What is wrong with this code, if i print address or name, it will works fine.
Below is the console data am getting,for reffrenceOutput
If you were to add a fourth named argument to the createMarker function you can then assign it as a property of the marker itself - which makes it quite simple to access when clicking the marker as you can use this
That said I do not see that you actually use the name nor the address arguments within the function itself so if again they are assigned as custom properties for the marker you can access them in the click event using this - ie: this.name etc
function createMarker( latlng, name, address, servicename ) {
var marker = new google.maps.Marker({
html:servicename,
map:map,
draggable:true,
animation:google.maps.Animation.DROP,
position:latlng,
name:name,
address:address,
icon: {
url:"{{ asset('img/new_map.png') }}"
}
});
google.maps.event.addListener(marker, 'click', function(e) {
infoWindow.setContent( this.html );
infoWindow.open( map, this );
}.bind( marker ));
markers.push( marker );
return marker;
}
After our brief discussion and thinking further about your requirements perhaps you might try like this. As you have ( as you stated ) already added the 4th argument we can add as a custom property to each marker. In the click handler we can iterate over the markers array and compare the current markers html attribute/property ( you originally refer to html hence continuing to do so here ) to the html property of whatever marker in the array and if they match add this to the output to be displayed in the infowindow
function createMarker( latlng, name, address, servicename ) {
var marker = new google.maps.Marker({
html:servicename,
map:map,
draggable:true,
animation:google.maps.Animation.DROP,
position:latlng,
name:name,
address:address,
icon: {
url:"{{ asset('img/new_map.png') }}"
}
});
google.maps.event.addListener( marker, 'click', function(e) {
let data=[];
markers.forEach( mkr=>{
if( mkr.html==this.html ){
data.push( mkr.html )
}
});
infoWindow.setContent( data.join( '<br />' ) );
infoWindow.open( map, this );
}.bind( marker ));
markers.push( marker );
return marker;
}
A fully working demo ( apikey redacted ) based upon the following XML file. The ajax function and it's callback are simply to emulate whatever mechanism used in your code to load markers onto the map, once loaded they do not get used again - the querying of markers is done solely based upon the markers array.
<?xml version="1.0"?>
<markers>
<marker servicename='a' name="Kinnettles" address="B9127, Angus DD8 1, UK" lat="56.61543329027024" lng="-2.9266123065796137"/>
<marker servicename='b' name="Nathro" address="1 Goynd Steading, Glenogil, Forfar, Angus DD8 3SW, UK" lat="56.793249595719956" lng="-2.8623101711273193"/>
<marker servicename='a' name="ArkHill" address="3 Dryburn Cottages, Glenogilvy, Forfar, Angus DD8 1UP, UK" lat="56.57065514278748" lng="-3.0511732892761074"/>
<marker servicename='b' name="DoddHill" address="4 Backmuir Rd, Duntrune, Tealing, Dundee, Angus DD4 0PT, UK" lat="56.54251020079966" lng="-2.9051538305053555"/>
<marker servicename='c' name="Govals" address="B9127, Forfar, Angus DD8, UK" lat="56.582320876071854" lng="-2.9509015874633633"/>
<marker servicename='d' name="Carsegownie" address="B9134, Forfar, Angus DD8, UK" lat="56.67951330362271" lng="-2.8062983350524746"/>
<marker servicename='a' name="Frawney" address="Kerton Farm, Forfar, Angus DD8, UK" lat="56.56806620951482" lng="-2.9501720266113125"/>
<marker servicename='a' name="NorthTarbrax" address="4 Nether Finlarg Farm Cottages, Forfar, Angus DD8 1XQ, UK" lat="56.57144715546598" lng="-2.92476614282225"/>
<marker servicename='e' name="TheCarrach" address="B951, Kirriemuir, Angus DD8, UK" lat="56.6938437674986" lng="-3.131382067657455"/>
<marker servicename='f' name="Glaxo" address="5 Meridian St, Montrose, Angus DD10 8DS, UK" lat="56.70431711148748" lng="-2.4660869436035"/>
</markers>
The html
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='utf-8' />
<title>Collate attributes from multiple markers to display in single InfoWindow</title>
<style>
#map{width:800px;height:600px;}
</style>
<script>
var map;
var markers=[];
var infoWindow;
function ajax(callback){
let xhr=new XMLHttpRequest();
xhr.onreadystatechange=function(){
if( this.status==200 && this.readyState==4 )callback(this.response)
}
xhr.open( 'GET', 'maps.xml', true );
xhr.send( null );
};
function loadmarkers(r){
let oParser=new DOMParser();
let oXML=oParser.parseFromString( r, 'application/xml' );
let nodes=oXML.documentElement.getElementsByTagName('marker');
for( let i=0; i < nodes.length; i++ ){
let latlng=new google.maps.LatLng( nodes[i].getAttribute('lat'),nodes[i].getAttribute('lng') );
let name=nodes[i].getAttribute('name');
let address=nodes[i].getAttribute('address');
let servicename=nodes[i].getAttribute('servicename');
createMarker(latlng,name,address,servicename)
}
};
function createMarker( latlng, name, address, servicename ) {
var marker = new google.maps.Marker({
html:servicename,
map:map,
draggable:true,
animation:google.maps.Animation.DROP,
position:latlng,
name:name,
address:address
});
google.maps.event.addListener( marker, 'click', function(e) {
/* query XML to find ALL nodes that have the same location */
let data=[
this.name,
this.address
];
markers.forEach( mkr=>{
if( mkr.html==this.html ) data.push( mkr.html );
});
infoWindow.setContent( data.join( '<br />' ) );
infoWindow.open( map, this );
}.bind( marker ));
markers.push( marker );
return marker;
};
function initMap(){
let centre=new google.maps.LatLng( 56.7, -2.8 );
let options = {
zoom: 10,
center: centre,
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true,
mapTypeControl: false,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
mapTypeIds: ['roadmap', 'terrain','satellite','hybrid']
}
};
map=new google.maps.Map( document.getElementById('map'), options );
infoWindow=new google.maps.InfoWindow();
ajax( loadmarkers );
}
</script>
<script async defer src='//maps.googleapis.com/maps/api/js?key=xxx&callback=initMap'></script>
</head>
<body>
<div id='map'></div>
</body>
</html>
I'm designing a webpage that will be able to retrieve a marker field[geopoint] that is similar for all documents in the collection from firestore and displays all the different documents' fields in an infowindow.
However, on retrieving the marker, I can only see one marker and its fields and not the rest of the other documents' fields.
Screenshots of the collection:
document1 document2 document3
On clicking the marker, only one document is being displayed on the map
Here's the code:
<?php
include_once 'header.php';
?>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-firestore.js"></script>
<div id="map"></div>
<!------ Include the above in your HEAD tag ---------->
<script>
firebase.initializeApp({
apiKey: "xxxxxxxxxxx",
authDomain: "xxxxxxxxxxx",
projectId: "xxxxxxxxxxx"
});
const db = firebase.firestore();
db.settings({timestampsInSnapshots: true});
var map;
var marker;
var infowindow;
var green_icon = 'http://maps.google.com/mapfiles/ms/icons/green-dot.png' ;
var purple_icon = 'http://maps.google.com/mapfiles/ms/icons/purple-dot.png' ;
function initMap() {
var options = {
zoom: 8,
center: {lat: 1.2921, lng: 36.8219}
};
var map = new google.maps.Map(document.getElementById('map'),options);
function addMarker(coords, icon, content, animation){
var marker = new google.maps.Marker({
position: coords,
map: map,
icon: icon,
animation: animation
});
var infoWindow = new google.maps.InfoWindow({
content: content
});
marker.addListener('click', function() {
infoWindow.open(map,marker);
});
}
db.collection('Nairobi').get().then((snapshot) => {
// var data = snapshot.data();
snapshot.docs.forEach(function(child){
var name_loc = child.id;
var loc = child.data().marker;
var forward = child.data().ForwardPower;
var reflected = child.data().ReflectedPower;
var ups = child.data().UPSError;
var upsDesc = child.data().UPSDesc;
var trans = child.data().TransmitterError;
var transDesc = child.data().TransDesc;
addMarker(
{lat: loc.latitude, lng: loc.longitude },
'http://maps.google.com/mapfiles/ms/icons/green-dot.png', '' +
`<h1> ${name_loc}</h1>` + "<br/>"
+ `<h2> Forward Power: ${forward} </h2>`
+ "<br/>" + `<h2> Reflected Power: ${reflected} </h2>`
+ "<br/>" + `<h2> UPS Error: ${ups} </h2>`
+ "<br/>" + `<h2> TransmitterError: ${trans} </h2>`
);
console.log(child.id, child.data());
});
})
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?language=en&key=[API KEY]&callback=initMap">
</script>
On the web console, there is no error and I get back arrays of the documents as shown below: console
You have exactly the same values of markers for the three Firestore documents! So the markers are stacked on your map and you only see one.
Just change the values and you will see the three different markers since your code works.
Also note that you could do:
snapshot.forEach(function(child){...})
instead of
snapshot.docs.forEach(function(child){...})
See https://firebase.google.com/docs/reference/js/firebase.firestore.QuerySnapshot?authuser=0#for-each
As an addition to Renaud's answer, this is indeed intended behaviour, by default Google Maps API displays only top marker.
To achieve desirable behaviour you can use OverlappingMarkerSpiderfier library, for example.
I'm creating a flask app and try to fetch coordinates from mysql DB, the database has latitude and longitude infomation, I'd like to show all of markers on the page with the lat/lng and tend to using js to add markers, don't know why it doesn't work. Any helps appreciated.
using flask sqlalchemy to get lat/lng info
<script>
$(document).ready(function () {
function initMap() {
var latlng = {lat: -37.8253632, lng: 144.1404107}; // THIS IS CENTER OF THE MAP
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: latlng
});
google.maps.event.addListenerOnce(map, 'tilesloaded', addMarkers);
function addMarkers() {
{% for CarD in page_data %}
var point = {lat: {{ CarD.lat }}, lng: {{ CarD.lng }} };
var marker = new google.maps.Marker({
position: point,
map: map,
title: '!'
});
{% endfor %}
marker['infowindow'] = new google.maps.InfoWindow({
content: '<div id="content" style="text-align: center"></div>'
}); // info of the point
}
}
});
</script>
Your jinja templates are processed on the server side so putting the python variables in javascript only works if the js is in your template (as in you have the html and js in the same .html file). Additionally, i would discourage you from mixing the code. I would recommend you make an ajax call and receive a json response with your points. In flask you can do something like this
#app.route('/api/coordinates)
def coordinates():
addresses = session.query(Coordinates)#however you query your db
all_coods = [] # initialize a list to store your addresses
for add in addresses:
address_details = {
"lat": add.lat,
"lng": add.lng,
"title": add.title}
all_coods.append(address_details)
return jsonify({'cordinates': all_coods})
then in your javascript you can call this endpoint then process the json object (I like to use fetch for my ajax calls)
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 16,
center: new google.maps.LatLng(-33.91722, 151.23064),
mapTypeId: 'roadmap'
});
//variable to hold your endpoint
var coodAddresses = 'https://yoursite.com/api/coordinates';
//an array to hold your cordinates
var locations = [];
//Using fetch to process the ajax call
// if you use fetch, besure to include the source below this line in your template
//<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.js"></script>
fetch(coodAddresses)
.then(function(response) {
return response.text();
}).then(function(body) {
var obj = JSON.parse(body);
var myAdd = {};
var addresses = obj.cordinates;
var l = addresses.length;
for (i = 0; i < l; i++) {
myAdd = {
position: {
lat: parseFloat(obj.cordinates[i].lat),
lng: parseFloat(obj.cordinates[i].lng)
},
title: obj.cordinates[i].title,
};
locations.push(myAdd);
}
locations.forEach(function(feature) {
var marker = new google.maps.Marker({
position: feature.position,
title: feature.title,
map: map
});
});
}).catch(function() {
// if the ajax call fails display an error in an info window
var pos = {
lat: lat,
lng: lng
};
infoWindow.setMap(map);
infoWindow.setPosition(pos);
infoWindow.setContent('An error occurred, we are unable to retreive cordinates.');
});
}
I hope you find this useful. If your points are not near each other, you may need to make sure the bounds include all of them
I have a problem with JavaScript code
$.getJSON('#Url.Action("GetData", "Home")', function (data) {
$.each(data, function (i, item) {
var marker = new google.maps.Marker({
'position': new google.maps.LatLng(item.GeoLong, item.GeoLat),
'map': map,
'title': item.PlaceName
});
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/blue-dot.png')
var infowindow = new google.maps.InfoWindow({
content: '#Html.ActionLink("Details","Details",new { id= '+item.Id+'})'
});
How to pass Id to controller using #Html.ActionLink?
In the controller I have a POST version of the Index method. How do I pass the Id using the ActionLink in this method?
In View I try to take ViewBag but nothing is displayed
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(int id)
{
ViewBag.id = id;
return RedirectToAction("Index", "Home");
}
EDIT:
Code of my View:
#{
ViewBag.Title = "Home Page";
}
Id : #ViewBag.id
<script src="http://maps.google.com/maps/api/js? key=**********" type="text/javascript"></script>
<style>
.stationInfo {
height: 150px;
width: 250px;
}
</style>
<div id="canvas" style="height: 600px; width:600px;"></div>
#section scripts {
<script type="text/javascript">
$(document).ready(function () {
GetMap();
});
function GetMap() {
google.maps.visualRefresh = true;
var Moscow = new google.maps.LatLng(55.752622, 37.617567);
var mapOptions = {
zoom: 15,
center: Moscow,
mapTypeId: google.maps.MapTypeId.G_NORMAL_MAP
};
var map = new google.maps.Map(document.getElementById("canvas"), mapOptions);
var myLatlng = new google.maps.LatLng(55.752622, 37.617567);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Name'
});
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/red-dot.png')
$.getJSON('#Url.Action("GetData", "Home")', function (data) {керы
$.each(data, function (i, item) {
var marker = new google.maps.Marker({
'position': new google.maps.LatLng(item.GeoLong, item.GeoLat),
'map': map,
'title': item.PlaceName
});
marker.setIcon('http://maps.google.com/mapfiles/ms/icons/blue-dot.png')
var infowindow = new google.maps.InfoWindow({
content:
'<form action="#Url.Action("Index", "Home")" method="POST">' +
'<input type="hidden" name="id"/>' +
'<a class="f" href="#" data-id="' + item.Id + '">Details</a></form>'
});
google.maps.event.addListener(marker, 'click', function () {
infowindow.open(map, marker);
});
})
});
$(function () {
$(document).on("click", "a.f", function (e) {
e.preventDefault();
var v = $(this).data("id");
var f = $(this).closest("form");
f.find("[name='id']").val(v);
f.submit();
});
});
}
</script>
}
But when I click on the link after the redirect ViewBag is empty(
you can't pass param from javascript to razor. but you can try to inject the id to the link after he is been generated :
var link = '#Html.Action("Details","Details")'+'/'+item.id;
var infowindow = new google.maps.InfoWindow({
content: 'details'
});
for the updated questio try to do this :
[HttpPost]
public ActionResult Index(int id)
{
ViewBag.id = id;
return Index();
}
It does not work that way because your loop executes on the client side and your server code (Html.ActionLink call) executes way before that in the server.
What you can do is, Use the Url.Action method to generate the path without the route values and append that with your dynamic variable.
This should work.
var infowindow = new google.maps.InfoWindow({
content: 'Details'
});
Replace Home with your controller name where you have the Details action method is available.
EDIT : As per the comment
In the controller I have a POST version of the Index method. How do I
pass the Id ?
If you do not prefer to pass the value in the querystring in GET request, but prefer a form post, you can submit a form. Build a form element for each item with a hidden input with name attribute value set to "Id" (same as your action method parameter name). You may keep the Id value in html5 data attribute which you will read later.
var infowindow = new google.maps.InfoWindow({
content: '<form action="#Url.Action("Index", "Home")" method="POST">' +
'<input type="hidden" name="id"/>' +
'<a class="f" href="#" data-id="' + item.Id + '">Details</a></form>'
});
Now we need a little javascript to hijack the normal link click behavior. When user clicks the link, we need to read the data attribute value we set (the Id value) and set that as the hidden input field value and submit the form.
$(function(){
$(document).on("click","a.f",function(e) {
e.preventDefault();
var v = $(this).data("id");
var f = $(this).closest("form");
f.find("[name='id']").val(v);
f.submit();
});
});
I am using the google maps API to show the last position a form was submitted to my site. So I am pulling the lon and lat values from a php file as variables but I need the script to refresh every 5 seconds so that the maps marker updates without page reload.
Here is the google api script:
<script>
function initialize() {
var myLatlng = new google.maps.LatLng<?php
require($DOCUMENT_ROOT . "php_includes/mobile_loc.php");
?>;
var mapOptions = {
zoom: 15,
center: myLatlng
}
var map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Last Scan'
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
And here is the php file:
<?php
include_once("php_includes/db_conx.php");
$sql = "SELECT * FROM patdub ORDER BY STR_TO_DATE(Timestamp, '%d/%m/%Y %H:%i:%s') DESC LIMIT 1";
$query = mysqli_query($db_conx, $sql);
$row = mysqli_fetch_array($query);
$lon = $row['Lon'];
$lat = $row['Lat'];
echo "($lat, $lon)";
?>
Any ideas? I've tried different AJAX methods but just can't seem to figure it out!
Edit: The line of code below is basically the bit I need to refresh every 5 seconds but without any div tags or anything because that interferes with the google api script..
<?php require($DOCUMENT_ROOT . "php_includes/mobile_loc.php"); ?>;
You want to call load the file your PHP script is in, assuming that it is in it's own file, you would do that like so and you can then update your DOM using the return from the AJAX call.
You would wrap the AJAX call in a javascript loop such as setInterval() like this:
setInterval(function() {
$.ajax({
url: "php_script.php"
}).done(function(return) {
console.log(return);
});
, 5000);
To call it every 5 seconds.
To incorportate it with your Google function (I have no knowledge of google maps so this may not be 100% accurate):
<script>
function initialize(myLatlng) {
myLatlng = myLatlng || new google.maps.LatLng<?php require($DOCUMENT_ROOT . "php_includes/mobile_loc.php");?>;
var mapOptions = {
zoom: 15,
center: myLatlng
}
var map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Last Scan'
});
}
google.maps.event.addDomListener(window, 'load', initialize);
setInterval(function() {
$.ajax(function() {
url: 'php_script.php'
}.done(function(response) {
var latlong = response;
initialize(latLong)
});
}, 5000)
</script>