0

I am working on a simple Google Maps app using the KnockoutJS library - or at least it seemed simple enough in concept. After reading up on KnockoutJS and working out some examples, I put together the initial parts. The html so far is just the map, I aim to populate the list as soon as I get over the first hurdle. The hurdle is in the Javascript. Here is the code for reference:

"use strict";

var map;
var center;
var defaultBounds;
var placesServices;

//LocationObject created to hold data for locations generated from google.places.nearbySearch
var LocationObject = function(data){

    this.position = data.geometry.location;
    this.lat = data.geometry.location.lat;
    this.lng = data.geometry.location.lng;
    this.name = data.name;
    this.placeID = data.place_id;
    this.rating = data.rating;
    this.types = data.types;
    this.linkToPhoto = data.html_attributions;

};



function initMap(){

    map = new google.maps.Map(document.getElementById('map'), {
        center: center,
        zoom: 17,
        mapTypeId: 'satellite',
        draggable: true, 
        zoomControl: false, 
        scrollwheel: true, 
        disableDoubleClickZoom: true
    });

    defaultBounds = new google.maps.LatLngBounds(
        new google.maps.LatLng(47.614217, -122.317981),new google.maps.LatLng(47.612975, -122.316291));
    map.fitBounds(defaultBounds);

    placesServices = new google.maps.places.PlacesService(map);

}


    //ViewModel created to observe changes on the map
var MapViewModel = function(){
    var self = this;

    self.testarr = ko.observableArray([
        { firstName: 'Bert', lastName: 'Bertington' },
        { firstName: 'Charles', lastName: 'Charlesforth' },
        { firstName: 'Denise', lastName: 'Dentiste' }
    ]);

    self.locations = ko.observableArray([]);
    self.markers = [];

    this.getNearbyLocations = function(){
        if(placesServices === undefined){
            placesServices = new google.maps.places.PlacesService(map);
        }

        var request = {
            location: center,
            radius: getBoundsRadius(defaultBounds),
            type: ['establishment']
        };

        placesServices.nearbySearch(request, function(results, status) {
            if (status === google.maps.places.PlacesServiceStatus.OK) {
                for (var i = 0; i <= 18; i++) {
                    var marker = new google.maps.Marker({
                        map: map,
                        position: results[i].geometry.location,
                        animation: google.maps.Animation.DROP
                    });
                    self.locations.push(new LocationObject(results[i]));
                    self.markers.push(marker);
                }
            } else{
                alert("We were not able to find any nearby locations in this Neighbourhood.");
            }
        });
    };

    this.init = function(){

        self.getNearbyLocations();

    };
};


var myMapViewModel = new MapViewModel();
myMapViewModel.init();
ko.applyBindings(myMapViewModel);   



/* Utility Functions */
function getBoundsRadius(bounds){....}

The error is:

Uncaught ReferenceError: google is not defined
at MapViewModel.getNearbyLocations

and I don't get why it's not being recognized here, when the map itself loads first without issue but here it get's hung up.

Here is the html for reference, but there shouldn't be an issue there:

<!DOCTYPE html>
<html lang="en">
  <head>
   <!-- Required meta tags -->
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

   <!-- Per Google guideline scheduled for the M65 release, css has been moved to an importer -->
   <link rel="import" href="importer.htm"></link>

   <!-- Bootstrap CSS -->
   <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">


  </head>
  <body>
   <div class="container-fluid">
    <div class="row">
        <div class="col-xs-12 col-md-4">
            <!-- List goes in this column. -->

            </div>
        </div>
        <div class="col-xs-12 col-md-8">
            <!-- Map goes into this column. -->
            <div id="map" style="width:100%;height:100vh;"></div>
        </div>
      </div>
     </div>

<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
<!-- Optional JavaScript -->
<script src="js/knockout.js" ></script>
<script src="js/app.js"></script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyC-1EdIyUOb74oGG_mEoPvJTAGCSJvSQms&callback=initMap&libraries=places"></script>
 </body>

aleksandar
  • 186
  • 12
  • Try adding maps script reference before `app.js` – adiga Oct 10 '17 at 07:26
  • You might also want to check out the answer to [this question](https://stackoverflow.com/questions/38627259/how-to-make-a-callback-to-google-maps-init-in-separate-files-of-a-web-app) – user3297291 Oct 10 '17 at 07:28

1 Answers1

1

I also thought that the error was because your app.js is being called before the maps script. But I tried changing it, same error, and I also tried removing the async parameter (as suggested by user3297291's comment), still the same error. Theoretically it should have worked.

But this worked - wrap the last 3 lines of your app.js code inside a ready() function:

$(document).ready(function(){
    var myMapViewModel = new MapViewModel();
    myMapViewModel.init();
    ko.applyBindings(myMapViewModel); 
});
Ray
  • 3,864
  • 7
  • 24
  • 36
  • Yeah, I tested all those alternatives yesterday as well - with the same result as you found. Also, because the map was loading and being stored in the globally declared variable I thought that it should be accessible. At one point, I tried an implementation where I would pass variables into the respective functions but that had the same result. I will add the jquery option tonight and approve once confirmed. – aleksandar Oct 10 '17 at 18:36
  • I ended up having to wrap it in a timeout, but this got me close enough - thanks! – aleksandar Oct 11 '17 at 04:48