3

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: enter image description here

my project setup

enter image description here

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 :- enter image description here

ANUBIS
  • 666
  • 1
  • 9
  • 20
  • You don't show your node.js code, but I would guess you don't have a node.js route to serve your JS file: [Resources not loading in Express](https://stackoverflow.com/questions/34505215/resources-not-loading-in-express/34506377#34506377) and [Serving static Javascript files with node.js](https://stackoverflow.com/questions/44680410/serving-static-javascript-files-with-node-js-socket-io-and-express/44680656#44680656). – jfriend00 Apr 14 '18 at 02:04
  • Probably a dup of this: [Serving static Javascript files with node.js](https://stackoverflow.com/questions/44680410/serving-static-javascript-files-with-node-js-socket-io-and-express/44680656#44680656), but you don't show enough code to know for sure. – jfriend00 Apr 14 '18 at 02:07
  • i edited the post. check it. also my node code is literally nothing but `app.listen` to get it working. – ANUBIS Apr 14 '18 at 02:12
  • @ShubhamShukla no its the actual directory. you can check the picture i provided about the project structure. – ANUBIS Apr 14 '18 at 02:14
  • @jfriend00 i provided the `nodejs` code in the post. – ANUBIS Apr 14 '18 at 02:19

1 Answers1

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.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • it does now found the external js file BUT it doesn't show the map. – ANUBIS Apr 14 '18 at 02:36
  • @SharlSherif - Well what error shows in the browser console? We've now solved the 404 that your original question showed. – jfriend00 Apr 14 '18 at 02:37
  • it does render the page and the other elements except the `map div`. i added photo in another edit for the console error – ANUBIS Apr 14 '18 at 02:40
  • 1
    @SharlSherif - Per a Google search, it appears the ERR_BLOCKED_BY_CLIENT may be due to your local ad blocker. You can search for that error yourself and find lots of discussion of it. Here's one discussion of it: https://www.keycdn.com/support/how-to-solve-err-blocked-by-client/ – jfriend00 Apr 14 '18 at 02:45
  • well that wasn't the reason why it doesn't load the map. it was the API link couldn't find where `initMap` callback function is. so this post helped me : https://stackoverflow.com/questions/32496382/typeerror-window-initmap-is-not-a-function Thank you so much for pointing out the directory thing. i feel super newbie now. – ANUBIS Apr 14 '18 at 02:58