"using API key multiple times" error after adding API Key to an old Google Maps API project

809 Views Asked by At

Finally getting around to fixing the well-known problem "API Key" error on a Google map I created back in 2014 (before you needed an API key for Google Maps API). I obtained a key and put this in the <head> (obviously substituting the real key for MY_API_KEY):

    <script async defer
    src="https://maps.googleapis.com/maps/api/js?key=MY_API_KEY&callback=initMap">
    </script>

and taking out the old <body onLoad="initMap()"> leaving just the <body> tag.

The map, which used to work while just warning me about the API key, now fails almost completely (shows the background map but none of the markers that should be on it), with first an error in the Chrome dev tools saying that I am using the API key multiple times ("You have included the Google Maps JavaScript API multiple times on this page. This may cause unexpected errors."), and then a lot of errors along this line:

InvalidValueError: setPosition: not a LatLng or LatLngLiteral: in property lat: not a number
InvalidValueError: setMap: not an instance of Map; and not an instance of StreetViewPanorama

A lot of the code is based on markers with labels.

Also have a bunch of infowindows along this line:

var intertidalObj = {
    "Intertidal":{name:"Intertidal", infowindow: new google.maps.InfoWindow({maxWidth:520, position: new google.maps.LatLng(48.69176776907712, -122.90861248970032),
      content: "<p class='iw'><strong>Intertidal Community</strong><br>The intertidal zone, also known as the foreshore and seashore, is the area that is above water at low tide and under water at high tide (in other words, the area between tide marks). This area can include many different types of habitats, with many types of animals, such as sea stars, sea cucumbers, sea urchins, crabs, barnacles, octopus, squid, anemones and worms.<br><br><a href='http://www.kwiaht.org'  target='_blank'>Kwiáht</a> and <a href='http://www.irthlingz.org'  target='_blank'>Irthlingz</a> are currently working with Laura Tidwell’s Orcas Middle School marine science students to create an interactive map of Indian Island's rich and fascinating intertidal community.<br><br><img class='pic' src='http://www.monumentalmap.com/monumentalmap/indian_island/intertidal.jpg'><br>Sources: <a href='https://sites.google.com/site/indianislandproject/identification-guides/birds' target='_blank'>Kwiaht</a> and <a href='http://en.wikipedia.org/wiki/Intertidal_zone' target='_blank'>Wikipedia</a></p><br>"}),coordinates:[48.69176776907712, -122.90861248970032]}
        };

google.maps.event.addListener(intertidalObj["Intertidal"].infowindow,'closeclick',function(){
    document.getElementById("Intertidal").checked = false;
});

I also tried putting the async defer inside the <body> instead of in the <head>. That didn't work, and from my Googling, it seems the <head> is the right place. Any suggestions? I'm not aware of any other options to try.

edit: @geocodezip: Your suggestion seems correct, but after I eliminated the line you suggest, I got the following errors in Chrome dev tools:

Uncaught ReferenceError: google is not defined
    at eval (eval at <anonymous> (markerwithlabel.min.js:1), <anonymous>:1:641)
    at markerwithlabel.min.js:1
VM25:1 Uncaught (in promise) TypeError: MarkerLabel_.getSharedCross is not a function
    at new MarkerLabel_ (eval at <anonymous> (markerwithlabel.min.js:1), <anonymous>:1:601)
    at new MarkerWithLabel (eval at <anonymous> (markerwithlabel.min.js:1), <anonymous>:1:9546)
    at initMap ((index):171)
    at js?key=MY_API_KEY&callback=initMap:125
    at js?key=MY_API_KEY&callback=initMap:125

Since it was saying that google was not defined, I thought maybe I needed to move the async defer up to the top of the <head> section. I tried that, and got the following error:

monumentalmap.com/:1 Uncaught (in promise) 
Wc {message: "initMap is not a function", name: "InvalidValueError", stack: "Error↵    at new Wc (https://maps.googleapis.com/m…&callback=initMap:125:108"}
message: "initMap is not a function"
name: "InvalidValueError"

Currently, the less functional one has the defer async near the top of the <head> and the dev console is showing:

VM511:1 Uncaught ReferenceError: google is not defined
    at eval (eval at <anonymous> (markerwithlabel.min.js:1), <anonymous>:1:641)
    at markerwithlabel.min.js:1
(anonymous) @ VM511:1
(anonymous) @ markerwithlabel.min.js:1
VM511:1 Uncaught (in promise) TypeError: MarkerLabel_.getSharedCross is not a function
    at new MarkerLabel_ (eval at <anonymous> (markerwithlabel.min.js:1), <anonymous>:1:601)
    at new MarkerWithLabel (eval at <anonymous> (markerwithlabel.min.js:1), <anonymous>:1:9546)

I have a feeling I just need to put the async defer in the right place. But not sure where that is.

1

There are 1 best solutions below

0
user1147171 On

What finally worked for me was:

1) eliminating markerwithlabel.min.js

2) creating an object literal (fishObj in the sample code below) whose properties are a bunch of object literals (e.g. lingcod, threespine stickleback, tubesnout, northern clingfish and Pacific sand lance below -- in reality there are a lot more of these), each with three properties: a name, an infowindow, and coordinates (latitude/longitude)

3) using a for/in loop to iterate over the "container" object (fishObj) with plain old new google.maps.Marker (instead of new MarkerWithLabel that I used previously) to instantiate the objects on the map, at the same time adding a label property (as well as some other properties) to each object. (Most of these properties are left over from my previous approach, and some may no longer be necessary or have any effect. One that does work is title which creates a tooltip.)

4) continuing to use async defer:

<script async defer src="https://maps.googleapis.com/maps/api/js?key=MY_API_KEY&callback=initMap">
    </script>

Check out the map here: http://monumentalmap.com.s3-website-us-west-2.amazonaws.com/

Here's some sample code:

var fishObj = {
    "lingcod":{name:"lingcod",infowindow: new google.maps.InfoWindow({maxWidth:340,content: "<p class='iw'>Only juveniles lingcod have been observed in Fishing Bay. Jaws have small pointed teeth interspersed with larger fang-like teeth. Lingcod are voracious predators, said to eat anything they can get into their mouths, including invertebrates and many species of fish.</p><img class='pic'  src='http://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Lingcod1.JPG/320px-Lingcod1.JPG'><br>Sources: <a href='https://sites.google.com/site/indianislandproject/identification-guides/fish-1/scorpaeniformes' target='_blank'>Kwiaht</a> and <a href='http://upload.wikimedia.org/wikipedia/commons/thumb/0/01/Lingcod1.JPG/320px-Lingcod1.JPG' target='_blank'>Wikimedia</a>"}),coordinates:[48.69352058493678, -122.90759325027466]},
    "threespine stickleback":{name:"threespine stickleback",infowindow: new google.maps.InfoWindow({maxWidth:420, content: "<p class='iw'>A small fish characterized by a row of three dorsal spines in front of the dorsal fin. Both adults and juveniles have been observed in Fishing Bay.</p><img class='pic'  src='http://1.bp.blogspot.com/_ODUGlGhaapI/TDmWSpDD6QI/AAAAAAAASbQ/HTrhqQOYYxI/s400/three+spined+stickleback.JPG'><br>Sources: <a href='https://sites.google.com/site/indianislandproject/identification-guides/fish-1/gasterosteiformes' target='_blank'>Kwiaht</a> and <a href='http://1.bp.blogspot.com/_ODUGlGhaapI/TDmWSpDD6QI/AAAAAAAASbQ/HTrhqQOYYxI/s400/three+spined+stickleback.JPG' target='_blank'>Wikimedia</a>"}),coordinates:[48.69369409272266,-122.90797412395477]},
    "tubesnout":{name:"tubesnout",infowindow: new google.maps.InfoWindow({maxWidth:420 , content: "<p class='iw'>A small fish characterized by a row of three dorsal spines in front of the dorsal fin. Both adults and juveniles have been observed in Fishing Bay.</p><img class='pic' src='https://lh3.googleusercontent.com/-JyYhERNz7_4/TfO3ylAdb0I/AAAAAAAAAeY/fKS4T8oBHQ0/s400/Tubesnout%2Bcloseup.JPG'><br>Sources: <a href='https://sites.google.com/site/indianislandproject/identification-guides/fish-1/gasterosteiformes' target='_blank'>Kwiaht</a> and <a href='http://1.bp.blogspot.com/_ODUGlGhaapI/TDmWSpDD6QI/AAAAAAAASbQ/HTrhqQOYYxI/s400/three+spined+stickleback.JPG' target='_blank'>Wikimedia</a>"}),coordinates:[48.69282300696724,-122.90957272052765]},
    "northern clingfish":{name:"northern clingfish",infowindow: new google.maps.InfoWindow({maxWidth:420 , content: "<p class='iw'>In this unique fish, the pelvic fin has evolved into a suction cup which the clingfish uses to latch onto rocks or kelp. The clingfish uses its suction cup as an anchor, prying prey off rocks with its head and bottom teeth. The suction cup also serves as a reservoir, storing water during times of low tide. </p><img class='pic' src='https://lh6.googleusercontent.com/-pgwRs03MAyc/Tg61AIfX5BI/AAAAAAAAAiI/UVGsGulEog8/s400/northern%2Bclingfish.png'><br>Source: <a href='https://sites.google.com/site/indianislandproject/identification-guides/fish-1/gobiesociformes' target='_blank'>Kwiaht</a>"}),coordinates:[48.692776973560925, -122.90755569934845]},
      "Pacific sand lance":{name:"Pacific sand lance",infowindow: new google.maps.InfoWindow({maxWidth: 500, content: "<p class='iw'>The sand lance derives its name from its slender body and pointed snout. The family name (and genus name, <em>Ammodytes</em>) means 'sand burrower', which describes the sand lance's habit of burrowing into sand to avoid tidal currents. Sand lances compose 35% of the diet of juvenile salmon. Juvenile chinook salmon depend on the sand lance for 60% of their diet. Only juvenile sand lances have been observed in Fishing Bay. </p><img class='pic' src='http://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Ammodytes_hexapterus.jpg/480px-Ammodytes_hexapterus.jpg'> <br>Sources: <a href='https://sites.google.com/site/indianislandproject/identification-guides/fish-1/perciformes' target='_blank'>Kwiaht</a> and <a href='http://en.wikipedia.org/wiki/Sand_lance' target='_blank'>Wikipedia</a>"}),coordinates:[48.69411546619574, -122.90785610675812]}
 };

var fishMarkers=[];
var n = 0;  
for (var j in fishObj) {
  var loc = new google.maps.LatLng(fishObj[j].coordinates[0],fishObj[j].coordinates[1]);
fishMarkers[n] = new google.maps.Marker({
     position: loc,
     map: map,
     icon: fishIcon,
     draggable: true,
     raiseOnDrag: true,
     labelContent: fishObj[j].name,
     title: fishObj[j].name,  
     label: {text:fishObj[j].name, color: "#eb3a44", fontWeight: "bold", 
     fontSize: "16px"},
     labelAnchor: new google.maps.Point(10,15)
    });

Hoping this might help someone facing the same problems.