Callback function for the API link is not defined

138
April 14, 2018, at 6:22 PM

I'm using Node.js to make a simple google maps. its working only if i provided the code directly in a script tag. when i try to link it to an external file it doesn't work.

how it has to be done so everything isn't out of scope.

My browser console:

my project setup

my HTML

<!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>Maps</title>
</head>
<body>
  <div id="map"></div>
<script src=".././public/javascripts/main.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=mykey&libraries=places&callback=initMap" async defer></script>
</body>
</html>

my map code. its all working fine but the problem is linking it to the main HTML page.

let google = window.google; <-- didnt help -->
let map, infoWindow;
function initMap() {
   map = new google.maps.Map(document.getElementById('map'), {
      center: {lat: -34.397, lng: 150.644},
      zoom: 18,
      mapTypeControl: true,
      mapTypeId: google.maps.MapTypeId.HYBRID, // once the page loaded the user see a {satellite} map type of his location.
      mapTypeControlOptions: {
        style: google.maps.MapTypeControlStyle.DEFAULT,
        mapTypeIds: ['satellite','roadmap','hybrid']
      }
    });
    google.maps.event.addDomListener(window, 'load', initMap);
  infoWindow = new google.maps.InfoWindow;
        // Try HTML5 geolocation. get the user current location.
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
          let pos = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          };
          infoWindow.setPosition(pos);
          map.setCenter(pos);
          let centerControlDiv = document.createElement('div'); // creating {Center Map} button
          let centerControl = new CenterControl(centerControlDiv, map, pos);
           /* passing the {div} element we just created.
            and the {map} variable that contain the actual map.
            with the {pos} variable that contain the user location
            {lat,lng}.
          */
          centerControlDiv.index = 1;  // positioning the {My location} button
          centerControlDiv.style['padding-top'] = '10px'; // styling the {My location} button
          map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(centerControlDiv); // positioned into RIGHT-CENTER
      function CenterControl(controlDiv, map, center) {
            // We set up a variable for this since we're adding event listeners
            // later.
            let control = this;
            let marker = new google.maps.Marker({ // a red marker placed on the user location.
                  position: pos,
                  map: map,
                  title: 'Your current location',
                  animation: google.maps.Animation.DROP,
                  draggable:true,
                  id: 'marker'
            });
            // Set the center property upon construction
            control.center_ = center;
            controlDiv.style.clear = 'both';
            // Set CSS for the control border
            let goCenterUI = document.createElement('div');
            goCenterUI.id = 'goCenterUI';
            goCenterUI.title = 'Click to recenter the map';
            controlDiv.appendChild(goCenterUI);
            // Set CSS for the control interior
            let goCenterText = document.createElement('div');
            goCenterText.id = 'goCenterText';
            goCenterText.innerHTML = 'My location';
            goCenterUI.appendChild(goCenterText);
            // Set up the click event listener for 'My location': Set the center of
            // the map
            // to the current center of the control.
            goCenterUI.addEventListener('click', () => {
              let currentCenter = control.getCenter();
              map.setCenter(currentCenter);
              marker.setAnimation(google.maps.Animation.BOUNCE); // make the marker BOUNCE when {my location} button is pressed.
              setTimeout(()=> marker.setAnimation(null), 1500); // stop bouncing after 1.5seconds.
            });
            marker.addListener('drag', function(){ // while dragging the marker a popup notify the user dropping will change location.
                infoWindow.setContent('Drop to set a new location');
                infoWindow.open(map,marker);
                console.log('dragging..');
            });
            // change the location based on where the user drag & dropped the marker.
            marker.addListener('dragend', () => {
                infoWindow.close();
                let newCenter = map.getCenter();
                control.setCenter(marker.position); // set the location to the marker's position.
            });
            // marker BOUNCE when clicked then stop after 1.5seconds.
            marker.addListener('click', ()=>{
              if (marker.getAnimation() !== null){
                marker.setAnimation(null);
              } else{
                marker.setAnimation(google.maps.Animation.BOUNCE);
                setTimeout(()=> marker.setAnimation(null), 1500);
              }
              // open a popup to notify the user changing location is by dragging the marker.
              infoWindow.setContent('Drag to change your location');
              infoWindow.open(map,marker);
              setTimeout(()=>infoWindow.close(), 1100);
            });
          let requestPlacesDetails = {
            placeId : 'ChIJN1t_tDeuEmsRUsoyG83frY4'
          }
          let PlacesDetails = (results, status) =>{
            if(status == google.maps.places.PlacesServiceStatus.OK){
              for(let i = 0; i < results.length; i++){
                console.log(results[i]);
              }
            }
          }
          let service = new google.maps.places.PlacesService(map);
          service.getDetails(requestPlacesDetails, PlacesDetails); // get details about every place nearby the user location.
            /**
            * Define a property to hold the center state.
            * @private
            */
            CenterControl.prototype.center_ = null;
            /**
            * Gets the map center.
            * @return {?google.maps.LatLng}
            */
            CenterControl.prototype.getCenter = function() {
              return this.center_;
            };
            /**
            * Sets the map center.
            * @param {?google.maps.LatLng} center
            */
            CenterControl.prototype.setCenter = function(center) {
              this.center_ = center;
            };
          }
        }, function() {
          handleLocationError(true, infoWindow, map.getCenter());
        });
      } else {
        // Browser doesn't support Geolocation
        handleLocationError(false, infoWindow, map.getCenter());
      }
    }

    function handleLocationError(browserHasGeolocation, infoWindow, pos) {
      infoWindow.setPosition(pos);
      infoWindow.setContent(browserHasGeolocation ?
                            'Error: The Geolocation service failed.' :
                            'Error: Your browser doesn\'t support geolocation.');
      infoWindow.open(map);
    }
  export {initMap}

EDIT its not that it doesn't load. because if i do that:- everthing works just fine and as expected. so its more like it doesn't recongize the js file when its outside. i'm using hbs (handlebars) for the html code.

<html>
<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>Maps</title>
</head>
<style>/* Always set the map height explicitly to define the size of the div
 * element that contains the map. */
    #map {
      height: 100%;
    }
    /* Optional: Makes the sample page fill the window. */
    html, body {
      height: 100%;
      margin: 0;
      padding: 0;
    }
  #goCenterUI {
    background-color: #fff;
    border: 2px solid #fff;
    border-radius: 3px;
    box-shadow: 0 2px 6px rgba(0,0,0,.3);
    cursor: pointer;
    float: left;
    margin-bottom: 22px;
    text-align: center;
  }
  #goCenterText {
    color: rgb(25,25,25);
    font-family: Roboto,Arial,sans-serif;
    font-size: 15px;
    line-height: 25px;
    padding-left: 5px;
    padding-right: 5px;
    user-select: none;
  }
  #setCenterUI {
    margin-left: 12px;
  }
</style>
<body>
  <div id="map"></div>
  <p>TESTTESTEST</p>
</body>
<script src="https://maps.googleapis.com/maps/api/js?key=mykey&libraries=places&callback=initMap" async defer></script>
<script type='application/javascript'>

let map, infoWindow;
function initMap() {
   map = new google.maps.Map(document.getElementById('map'), {
      center: {lat: -34.397, lng: 150.644},
      zoom: 18,
      mapTypeControl: true,
      mapTypeId: google.maps.MapTypeId.HYBRID, // once the page loaded the user see a {satellite} map type of his location.
      mapTypeControlOptions: {
        style: google.maps.MapTypeControlStyle.DEFAULT,
        mapTypeIds: ['satellite','roadmap','hybrid']
      }
    });

  infoWindow = new google.maps.InfoWindow;
        // Try HTML5 geolocation. get the user current location.
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
          let pos = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          };
          infoWindow.setPosition(pos);
          map.setCenter(pos);
          let centerControlDiv = document.createElement('div'); // creating {Center Map} button
          let centerControl = new CenterControl(centerControlDiv, map, pos);
           /* passing the {div} element we just created.
            and the {map} variable that contain the actual map.
            with the {pos} variable that contain the user location
            {lat,lng}.
          */
          centerControlDiv.index = 1;  // positioning the {My location} button
          centerControlDiv.style['padding-top'] = '10px'; // styling the {My location} button
          map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(centerControlDiv); // positioned into RIGHT-CENTER
      function CenterControl(controlDiv, map, center) {
            // We set up a variable for this since we're adding event listeners
            // later.
            let control = this;
            let marker = new google.maps.Marker({ // a red marker placed on the user location.
                  position: pos,
                  map: map,
                  title: 'Your current location',
                  animation: google.maps.Animation.DROP,
                  draggable:true,
                  id: 'marker'
            });
            // Set the center property upon construction
            control.center_ = center;
            controlDiv.style.clear = 'both';
            // Set CSS for the control border
            let goCenterUI = document.createElement('div');
            goCenterUI.id = 'goCenterUI';
            goCenterUI.title = 'Click to recenter the map';
            controlDiv.appendChild(goCenterUI);
            // Set CSS for the control interior
            let goCenterText = document.createElement('div');
            goCenterText.id = 'goCenterText';
            goCenterText.innerHTML = 'My location';
            goCenterUI.appendChild(goCenterText);
            // Set up the click event listener for 'My location': Set the center of
            // the map
            // to the current center of the control.
            goCenterUI.addEventListener('click', () => {
              let currentCenter = control.getCenter();
              map.setCenter(currentCenter);
              marker.setAnimation(google.maps.Animation.BOUNCE); // make the marker BOUNCE when {my location} button is pressed.
              setTimeout(()=> marker.setAnimation(null), 1500); // stop bouncing after 1.5seconds.
            });
            marker.addListener('drag', function(){ // while dragging the marker a popup notify the user dropping will change location.
                infoWindow.setContent('Drop to set a new location');
                infoWindow.open(map,marker);
                console.log('dragging..');
            });
            // change the location based on where the user drag & dropped the marker.
            marker.addListener('dragend', () => {
                infoWindow.close();
                let newCenter = map.getCenter();
                control.setCenter(marker.position); // set the location to the marker's position.
            });
            // marker BOUNCE when clicked then stop after 1.5seconds.
            marker.addListener('click', ()=>{
              if (marker.getAnimation() !== null){
                marker.setAnimation(null);
              } else{
                marker.setAnimation(google.maps.Animation.BOUNCE);
                setTimeout(()=> marker.setAnimation(null), 1500);
              }
              // open a popup to notify the user changing location is by dragging the marker.
              infoWindow.setContent('Drag to change your location');
              infoWindow.open(map,marker);
              setTimeout(()=>infoWindow.close(), 1100);
            });
          let requestPlacesDetails = {
            placeId : 'ChIJN1t_tDeuEmsRUsoyG83frY4'
          }
          let PlacesDetails = (results, status) =>{
            if(status == google.maps.places.PlacesServiceStatus.OK){
              for(let i = 0; i < results.length; i++){
                console.log(results[i]);
              }
            }
          }
          let service = new google.maps.places.PlacesService(map);
          service.getDetails(requestPlacesDetails, PlacesDetails); // get details about every place nearby the user location.
            /**
            * Define a property to hold the center state.
            * @private
            */
            CenterControl.prototype.center_ = null;
            /**
            * Gets the map center.
            * @return {?google.maps.LatLng}
            */
            CenterControl.prototype.getCenter = function() {
              return this.center_;
            };
            /**
            * Sets the map center.
            * @param {?google.maps.LatLng} center
            */
            CenterControl.prototype.setCenter = function(center) {
              this.center_ = center;
            };
          }
        }, function() {
          handleLocationError(true, infoWindow, map.getCenter());
        });
      } else {
        // Browser doesn't support Geolocation
        handleLocationError(false, infoWindow, map.getCenter());
      }
    }

    function handleLocationError(browserHasGeolocation, infoWindow, pos) {
      infoWindow.setPosition(pos);
      infoWindow.setContent(browserHasGeolocation ?
                            'Error: The Geolocation service failed.' :
                            'Error: Your browser doesn\'t support geolocation.');
      infoWindow.open(map);
    }

</script>
</html>

my node code : -

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);

app.listen(4000, ()=>{
  console.log('server is up on 3000');
})
// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});
// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};
  // render the error page
  res.status(err.status || 500);
  res.render('error');
});
module.exports = app;

**EDIT 3 ** console error :-

Answer 1

Change this:

<script src=".././public/javascripts/main.js"></script>

to this:

<script src="/javascripts/main.js"></script>

The path you use in the web page for the resource needs to be relative to the public directory, not relative to the web page directory and should start with a /.

This line of code:

app.use(express.static(path.join(__dirname, 'public')));

Tells your express server to look in the public sub-directory for matching paths that are requested. So, when /javascripts/main.js is requested by the browser, it will look in public/javascripts/main.js which is where the file is located. The key here is that the URLs you use in your web pages need to assume the root is the directory in your express.static() which in your case is public. So, whatever URL is requested will be appended to the public path and should start with /.

As another example, if the browser requests /test.js, then your express.static() command will look for public/test.js. In order to look for public/javsacripts/main.js, you need to put /javascripts/main.js into the web page so that's what the browser requests.

READ ALSO
ReactJs: How to properly recieve server request

ReactJs: How to properly recieve server request

I have a problem with receiving server responseFirst GET /getAllCoursesByMajor receives the response and set the values to courses

166
Accessing Express.js local variables in client side JavaScript

Accessing Express.js local variables in client side JavaScript

Curious if I'm doing this right and if not how you guys would approach this

320
Hosting multiple nodejs on same server/domain name

Hosting multiple nodejs on same server/domain name

I'm intending to host an online portfolio and I have several nodejs projects I'd like to host

98
Sort does not work on Text query with parse-server

Sort does not work on Text query with parse-server

The parse-server documentation is a bit outdated: http://docsparseplatform

176