Javascript variable to Python - javascript

I'm working locally using Django, and I created a template of a map using Leaflet. After doing some research I find that you can let the user click on the map to create a Marker and then pressing a button (export) to download the geoJSON of every figure or marker the user created.
What I want to do is not to download the geoJSON but to store it on a Database (it could be locally). Im not proficient at JavaScript so I'm really really stuck.
This is the map code
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script>
L_NO_TOUCH = false;
L_DISABLE_3D = false;
</script>
<script src="https://cdn.jsdelivr.net/npm/leaflet#1.5.1/dist/leaflet.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet#1.5.1/dist/leaflet.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/>
<link rel="stylesheet" href="https://rawcdn.githack.com/python-visualization/folium/master/folium/templates/leaflet.awesome.rotate.css"/>
<style>html, body {width: 100%;height: 100%;margin: 0;padding: 0;}</style>
<style>#map {position:absolute;top:0;bottom:0;right:0;left:0;}</style>
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
#map_a3375e0d166f4ec89fd79df498d1f8b8 {
position: relative;
width: 100.0%;
height: 100.0%;
left: 0.0%;
top: 0.0%;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.css"/>
<style>
#export {
position: absolute;
top: 5px;
right: 10px;
z-index: 999;
background: white;
color: black;
padding: 6px;
border-radius: 4px;
font-family: 'Helvetica Neue';
cursor: pointer;
font-size: 12px;
text-decoration: none;
top: 90px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.css"/>
</head>
<body>
<div class="folium-map" id="map_a3375e0d166f4ec89fd79df498d1f8b8" ></div>
<a href='#' id='export'>Continue</a>
</body>
<script>
var map_a3375e0d166f4ec89fd79df498d1f8b8 = L.map(
"map_a3375e0d166f4ec89fd79df498d1f8b8",
{
center: [46.8527, -121.7649],
crs: L.CRS.EPSG3857,
zoom: 13,
zoomControl: true,
preferCanvas: false,
}
);
var tile_layer_0cce79173c4743718c558aeea7872020 = L.tileLayer(
"https://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.jpg",
{"attribution": "Map tiles by \u003ca href=\"http://stamen.com\"\u003eStamen Design\u003c/a\u003e, under \u003ca href=\"http://creativecommons.org/licenses/by/3.0\"\u003eCC BY 3.0\u003c/a\u003e. Data by \u0026copy; \u003ca href=\"http://openstreetmap.org\"\u003eOpenStreetMap\u003c/a\u003e, under \u003ca href=\"http://creativecommons.org/licenses/by-sa/3.0\"\u003eCC BY SA\u003c/a\u003e.", "detectRetina": false, "maxNativeZoom": 18, "maxZoom": 18, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
).addTo(map_a3375e0d166f4ec89fd79df498d1f8b8);
var options = {
position: "topleft",
draw: {"polyline": {"allowIntersection": false}},
edit: {"poly": {"allowIntersection": false}},
}
// FeatureGroup is to store editable layers.
var drawnItems = new L.featureGroup().addTo(
map_a3375e0d166f4ec89fd79df498d1f8b8
);
options.edit.featureGroup = drawnItems;
var draw_control_ca0cd7071ba049ccb3dafbbf098f2b38 = new L.Control.Draw(
options
).addTo( map_a3375e0d166f4ec89fd79df498d1f8b8 );
map_a3375e0d166f4ec89fd79df498d1f8b8.on(L.Draw.Event.CREATED, function(e) {
var layer = e.layer,
type = e.layerType;
var coords = JSON.stringify(layer.toGeoJSON());
layer.on('click', function() {
alert(coords);
console.log(coords);
});
drawnItems.addLayer(layer);
});
map_a3375e0d166f4ec89fd79df498d1f8b8.on('draw:created', function(e) {
drawnItems.addLayer(e.layer);
});
document.getElementById('export').onclick = function(e) {
var data = drawnItems.toGeoJSON();
var convertedData = 'text/json;charset=utf-8,'
+ encodeURIComponent(JSON.stringify(data));
document.getElementById('export').setAttribute(
'href', 'data:' + convertedData
);
document.getElementById('export').setAttribute(
'download', "my_data.geojson"
);
}
</script>
And I know this is the part I have to change
document.getElementById('export').onclick = function(e) {
var data = drawnItems.toGeoJSON();
var convertedData = 'text/json;charset=utf-8,'
+ encodeURIComponent(JSON.stringify(data));
document.getElementById('export').setAttribute(
'href', 'data:' + convertedData
);
document.getElementById('export').setAttribute(
'download', "my_data.geojson"
);
}
Could anyone give me some direction/tutorial of how to acchieve what I want?

I would highly recommend the fetch API. It's as close to a simple web request as you can get!
Your code might look like this:
// async function here allows you to use "await" keyword.
document.getElementById('export').onclick = async function(e) {
var data = drawnItems.toGeoJSON();
// make the request:
var rsp = await fetch("path/to/server/upload/url", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
});
console.log("server responded with: ", await rsp.json());
}
EDIT:
The answer to your question HIGHLY depends on which database technology you are using. Some database servers host an HTTP API that allows you to fetch directly to them, such as CouchDB, but this is exceedingly uncommon, even when using Couch (for security reasons, JavaScript in your browser has VERY limited IO options).
Here's the (by far) most common way to approach this problem:
send geoJSON from browser to server (code example above)
server saves JSON to database
You have stated you are using Django. That's the server tech in #2.
On the server, the path you will take is:
create a Django Route at the URL endpoint where you put your path/to/server/upload/url
In the route's python function, you will save the data to the database connected to Django.
In Django, database interactions are typically done via Django's ORM, but you can use any methodology you want at this point.
The code above shows you how to get the geoJSON data from browser JS to your Django server so you can save it to a DB.

Related

Javascript framework not working properly same code as jsfiddle?

<html>
<head>
<meta charset="UTF-8">
<title>Simple globe with iTowns</title>
<style>
html { height: 100%; }
body { margin: 0; overflow: hidden; height: 100%; }
#viewerDiv { margin: auto; height: 100%; width: 100%; padding: 0; }
canvas { display: block }
</style>
</head>
<body>
<div id="viewerDiv"></div>
<script src="https://cdn.jsdelivr.net/npm/itowns#2.32.0/dist/itowns.js </script>
<script type="text/javascript">
var viewerDiv = document.getElementById('viewerDiv');
var placement = {
coord: new itowns.Coordinates('EPSG:4326', 2.351323, 48.856712),
range: 25000000
};
var view = new itowns.GlobeView(viewerDiv, placement);
var orthoSource = new itowns.WMTSSource({
url: 'https://wxs.ign.fr/3ht7xcw6f7nciopo16etuqp2/geoportail/wmts',
crs: "EPSG:3857",
name: 'ORTHOIMAGERY.ORTHOPHOTOS',
tileMatrixSet: 'PM',
format: 'image/jpeg',
})
var orthoLayer = new itowns.ColorLayer('Ortho', {
source: orthoSource,
});
view.addLayer(orthoLayer);
var elevationSource = new itowns.WMTSSource({
url: 'https://wxs.ign.fr/3ht7xcw6f7nciopo16etuqp2/geoportail/wmts',
crs: 'EPSG:4326',
name: 'ELEVATION.ELEVATIONGRIDCOVERAGE.SRTM3',
tileMatrixSet: 'WGS84G',
format: 'image/x-bil;bits=32',
zoom: {min: 3, max: 10},
});
var elevationLayer = new itowns.ElevationLayer('MNT_WORLD', {
source: elevationSource,
});
view.addLayer(elevationLayer);
</script>
</body>
</html>
I am using a framework called iTowns and I have copied the code exactly from a jsfiddle they provided as an example. The jsfiddle loads Earth fine but my code does not properly load the land layer and instead I get a blue sphere. I get this error in the console,
"Failed to load resource: the server responded with a status of 403 (Forbidden)"
I am running the website on a live local server. What am I missing here?
http://jsfiddle.net/q70umk6r/
Hard to tell if your resources are available, but given that you're getting a 403, I'm guessing not.
you could try using cdn package instead though
<script src="https://cdn.jsdelivr.net/npm/itowns#2.32.0/dist/itowns.js"></script>
just because "https://wxs.ign.fr/3ht7xcw6f7nciopo16etuqp2/geoportail/wmts" server dont allow GET request that its request headers' Referer not "localhost:xx/xxx" or other Registered urls;

JS doesn't write info in txt

I'm new in js. So I installed node.js.
What I have: I have html file which opens a map in the browser. When user right click it should create txt file and write 'Learning how to write in a file' in it, but it doesn't.
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<script>
L_NO_TOUCH = false;
L_DISABLE_3D = false;
</script>
<script src="https://cdn.jsdelivr.net/npm/leaflet#1.5.1/dist/leaflet.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet#1.5.1/dist/leaflet.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/>
<link rel="stylesheet" href="https://rawcdn.githack.com/python-visualization/folium/master/folium/templates/leaflet.awesome.rotate.css"/>
<style>html, body {width: 100%;height: 100%;margin: 0;padding: 0;}</style>
<style>#map {position:absolute;top:0;bottom:0;right:0;left:0;}</style>
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
#map_fc81479c2a8c4f18ad55baf3c9ba4285 {
position: relative;
width: 100.0%;
height: 100.0%;
left: 0.0%;
top: 0.0%;
}
</style>
<script src="https://requirejs.org/docs/release/2.3.6/minified/require.js"></script>
</head>
<body>
<div class="folium-map" id="map_fc81479c2a8c4f18ad55baf3c9ba4285" ></div>
</body>
<script>
var map_fc81479c2a8c4f18ad55baf3c9ba4285 = L.map(
"map_fc81479c2a8c4f18ad55baf3c9ba4285",
{
center: [55.02111, 73.40751],
crs: L.CRS.EPSG3857,
zoom: 13,
zoomControl: true,
preferCanvas: false,
}
);
var tile_layer_216c8662dc00405dba72c81174fd5845 = L.tileLayer(
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
{"attribution": "Data by \u0026copy; \u003ca href=\"http://openstreetmap.org\"\u003eOpenStreetMap\u003c/a\u003e, under \u003ca href=\"http://www.openstreetmap.org/copyright\"\u003eODbL\u003c/a\u003e.", "detectRetina": false, "maxNativeZoom": 18, "maxZoom": 18, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
).addTo(map_fc81479c2a8c4f18ad55baf3c9ba4285);
var lat, lng;
map_fc81479c2a8c4f18ad55baf3c9ba4285.addEventListener('mousemove', function(ev) {
lat = ev.latlng.lat;
lng = ev.latlng.lng;
});
document.getElementById("map_fc81479c2a8c4f18ad55baf3c9ba4285").addEventListener("contextmenu", function (event) {
// Prevent the browser's context menu from appearing
event.preventDefault();
alert(lat + ' - ' + lng);
return false; // To disable default popup.
});
// Trying to save to text file
// !!!
// !!!
// !!!
// does not work :
const fs = require('fs')
let data = "Learning how to write in a file."
fs.writeFile('Output.txt', data, (err) => {
if (err) throw err;
})
</script>
and if I open console in the browser it shows me:
85 raw : const fs = require('fs')
But if I run code which should create a file in a separate js file - it creates good.
What should I do for it to create file when user right click on a map?
Edit 1:
Added script and still does not work
<script src="https://requirejs.org/docs/release/2.3.6/minified/require.js">
</script>
JavaScript is a browser based language for web. You cannot do anything outside the browser environment. Browsers don't give acess to the file system and other modules.
This is the issue that Node js solved. If you want to acess file system using javascript, I'll suggest to create an express web app using Node as backend allowing you to write into files and much more.
Feel free to Google Node and Express you'll get many examples online.
Hope this helps...

How to include an already existing extension from github into my main index.html code?

I am trying to implement an extension into my main code. I tried to copy the code and make my own but this didnt work or the extension was not visualised, I dont have a clue. This is the github page with the extension I would like to use: [link] (https://github.com/Autodesk-Forge/forge-rcdb.nodejs/tree/master/src/client/viewer.components/Viewer.Extensions.Dynamic/Viewing.Extension.IoT) Thank you in advance!
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no" />
<meta charset="utf-8">
<!-- The Viewer CSS -->
<link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/style.min.css" type="text/css">
<!-- Developer CSS -->
<style>
body {
margin: 0;
}
#MyViewerDiv {
width: 100%;
height: 100%;
margin: 0;
background-color: #F0F8FF;
}
</style>
</head>
<body>
<!-- The Viewer will be instantiated here -->
<div id="MyViewerDiv"></div>
<!-- The Viewer JS -->
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/6.*/viewer3D.min.js"></script>
<!-- Developer JS -->
<script>
var viewerApp;
var options = {
env: 'AutodeskProduction',
getAccessToken: function(onGetAccessToken) {
//
// TODO: Replace static access token string below with call to fetch new token from your backend
// Both values are provided by Forge's Authentication (OAuth) API.
//
// Example Forge's Authentication (OAuth) API return value:
// {
// "access_token": "<YOUR_APPLICATION_TOKEN>",
// "token_type": "Bearer",
// "expires_in": 86400
// }
//
var accessToken = 'eyJhbGciOiJIUzI1NiIsImtpZCI6Imp3dF9zeW1tZXRyaWNfa2V5In0.eyJjbGllbnRfaWQiOiJSRmcyZEh1TXFkemVuSjl2eng2ZWFScnhYRDczZ2RMMSIsImV4cCI6MTU2NzA3MjIxNywic2NvcGUiOlsiZGF0YTpyZWFkIiwiZGF0YTp3cml0ZSIsImRhdGE6Y3JlYXRlIiwiYnVja2V0OnJlYWQiLCJidWNrZXQ6Y3JlYXRlIl0sImF1ZCI6Imh0dHBzOi8vYXV0b2Rlc2suY29tL2F1ZC9qd3RleHA2MCIsImp0aSI6Ill0Ykozb0hxWDhIbGJMS0p2UDVkWWhEVEhPeUx1TXVxQWo4cnZSOW5LR2FIZmY4YmkweVQ4N2UzVXZvd2g0TWIifQ.Rq7TsewQlXl0VnSfzaR0bw7Vxgh4EOSf9xD9jqfg0b4';
var expireTimeSeconds = 60 * 30;
onGetAccessToken(accessToken, expireTimeSeconds);
}
};
let config3d = {
extensions: ['Autodesk.InViewerSearch']
};
var documentId = 'urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6amFuc3NlbnNfMjcwODIwMTkvSUZDJTIwU2NoZXBlbmRvbWxhYW4ucnZ0';
Autodesk.Viewing.Initializer(options, function onInitialized(){
viewerApp = new Autodesk.Viewing.ViewingApplication('MyViewerDiv');
viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D, config3d);
viewerApp.loadDocument(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
function onDocumentLoadSuccess(doc) {
// We could still make use of Document.getSubItemsWithProperties()
// However, when using a ViewingApplication, we have access to the **bubble** attribute,
// which references the root node of a graph that wraps each object from the Manifest JSON.
var viewables = viewerApp.bubble.search({'type':'geometry'});
if (viewables.length === 0) {
console.error('Document contains no viewables.');
return;
}
// Choose any of the avialble viewables
viewerApp.selectItem(viewables[0].data, onItemLoadSuccess, onItemLoadFail);
}
function onDocumentLoadFailure(viewerErrorCode) {
console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);
}
function onItemLoadSuccess(viewer, item) {
console.log('onItemLoadSuccess()!');
console.log(viewer);
console.log(item);
// Congratulations! The viewer is now ready to be used.
console.log('Viewers are equal: ' + (viewer === viewerApp.getCurrentViewer()));
}
function onItemLoadFail(errorCode) {
console.error('onItemLoadFail() - errorCode:' + errorCode);
}
</script>
</body>
You will need to build this extension before you can use it - see this repo here to build the extensions separately.
But this extension is locked in with React so you will need to strip the React bits off before you can with your frameworkless plain old HTML.
We are working on a revamp of both RCDB and Extension Library just to isolate the extensions from unnecessary dependencies like React - will come back to update this answer once that's done.

How to change map tile types on ui controls

When we are initializing the map, we set the baselayer to "reduced.day".
We are currently facing a problem, when the user changes the map type from "map-view" to "satellite" and back to "map-view", the tile changed to the standard and not "reduced.day".
I have looked up the docs, but canĀ“t find any hint on how to prevent that problem.
So my question is, how to set with the UI controls the map-view tiles to reduced day.
Thanks a lot.
I finally could achieve the solution for my problem.
The solution was to pass a custom object with the requested map style for each map type.
See below the complete code for editing the map controls.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Here Custom Controlls</title>
<script src="http://js.api.here.com/v3/3.0/mapsjs-core.js" type="text/javascript" charset="utf-8"
></script>
<script src="http://js.api.here.com/v3/3.0/mapsjs-service.js" type="text/javascript" charset="utf-8"
></script>
<script src="http://js.api.here.com/v3/3.0/mapsjs-ui.js" type="text/javascript" charset="utf-8"
></script>
<link rel="stylesheet" type="text/css" href="http://js.api.here.com/v3/3.0/mapsjs-ui.css"
/>
</head>
<body>
<div id="map" style="height: 800px; width: 800px;"></div>
<script type="text/javascript" charset="utf-8">
//Initialize the Platform object:
const platform = new H.service.Platform({
app_id: {YOUR_APP_ID},
app_code: {YOUR_APP_CODE}
});
// Get the default map types from the Platform object:
const defaultLayers = platform.createDefaultLayers();
// Instantiate the map:
const map = new H.Map(
document.getElementById("map"),
defaultLayers.normal.map,
{
zoom: 10,
center: { lng: 13.4, lat: 52.51 }
}
);
const mapTileService = platform.getMapTileService({ type: "base" });
var reduce = mapTileService.createTileLayer(
"maptile",
"reduced.day",
256,
"png8"
);
map.setBaseLayer(reduce);
// Create the custom UI:
const ui = H.ui.UI.createDefault(
map,
{
...defaultLayers,
normal: {
map: reduce
}
},
"de-DE"
);
</script>
</body>
</html>
Please see two javascript functions codes.
SatelliteLayer will work with type : 'aerial'.
ReducedLayer will work with type : 'base'.
/**
*
* #param {H.Map}
* #param {H.service.Platform}
*/
function setAerialSatelliteLayer(map, platform){
var mapTileService = platform.getMapTileService({
type: 'aerial'
});
var parameters = {};
var tileLayer = mapTileService.createTileLayer(
'maptile',
'satellite.day',
256,
'png8',
parameters
);
map.setBaseLayer(tileLayer);
}
/**
*
* #param {H.Map}
* #param {H.service.Platform}
*/
function setBaseReducedLayer(map, platform){
var mapTileService = platform.getMapTileService({
type: 'base'
});
var parameters = {};
var tileLayer = mapTileService.createTileLayer(
'maptile',
'reduced.day',
256,
'png8',
parameters
);
map.setBaseLayer(tileLayer);
}

Error trying to edit a script src attribute using jQuery

I'm trying to follow this Google Maps example, but instead of hardcoding my API KEY, I'm trying to fetch it from an API I created.
So, I created this HTML file. The KEY is properly fetched, but when I'm trying to set the script's src attribute on runtime (so I can add my own key to the URI), it's not getting added at all.
This is my HTML
<!DOCTYPE html>
<html>
<head>
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
crossorigin="anonymous"></script>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Simple markers example</title>
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map {
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
function initMap() {
var myLatLng = {lat: -25.363, lng: 131.044};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng
});
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'Hello World!'
});
}
</script>
<script async defer>
$.get( "maps_api_key", function( data ) {
const API_KEY = String(data)
console.log("API_KEY: " + API_KEY)
var uri = "https://maps.googleapis.com/maps/api/js?key=" + API_KEY + "&callback=initMap"
console.log("URI is: " + uri)
$("#maps_fetcher").attr("src", uri)
});
</script>
<script id="maps_fetcher" async defer
src="https://maps.googleapis.com/maps/api/js?key=API_KEY&callback=initMap">
console.log("Map fetcher")
</script>
</body>
</html>
The line at console.log("Map fetcher") is never being printed either.
For what it's worth, I'm serving the HTML through Node and Express.
Any ideas on what could be happening here?
Thanks in advance

Categories