Score:0

Google API callback doesn't work

jm flag

I've created this javascript (delivery.js) that is supposed to take a pre-existing div on a webform page and append a Google Map to it, along with a few circles of differing radius.

Here is my libraries.yml, I reference the GoogleMaps global in the script url to be used as the callback.

delivery:
  version: 1.x
  js:
    js/delivery.js: {}
  dependencies:
  - core/jquery
  - core/drupalSettings
maps:
  js:
    'https://maps.googleapis.com/maps/api/js?key=AIzaSyCP9_LHyWKv821WTcLWZd8GcLLHIHvPPU0&callback=GoogleMaps.initMap&v=weekly':  { type: external, minified: true }

.module file attaching the libraries:

function order_form_webform_handler_form_alter(&$form, &$form_state, $form_id) {
    if($form_id == "webform_submission_order_submission_node_5_add_form" || $form_id == "webform_submission_order_submission_test_form" ){
        $form['#attached']['library'][] = 'order_form_webform_handler/delivery';
        $form['#attached']['library'][] = 'order_form_webform_handler/maps';
    }
}

Finally, my delivery.js file that does all the work:

var GoogleMaps = GoogleMaps || {};
(function ($, Drupal, GoogleMaps) {
  
    Drupal.behaviors.attachMap = {
      attach: function () {

        GoogleMaps.initMap = function(){
          // Create the map.
          const map = new google.maps.Map(document.getElementById("edit-map"), {
            zoom: 4,
            center: { lat: 44.24, lng: -76.57 },
            mapTypeId: "terrain",
          });

          let radii = [10000, 15000, 20000, 30000];

          for(let i = 0; i < radii.length; i++){
            const cityCircle = new google.maps.Circle({
              strokeColor: "#FF0000",
              strokeOpacity: 0.8,
              strokeWeight: 2,
              fillColor: "#FF0000",
              fillOpacity: 0.35, 
              map: map,
              center: { lat: 44.24, lng: -76.57 },
              radius: radii[i],
            });
          }
        }
      }
    };
  
  })(jQuery, Drupal, GoogleMaps);

However, when I try to run this, I get this error:

.te {message: 'GoogleMaps.initMap is not a function', stack: 'Error\n at _.te.captureStackTrace (https://maps.PPU0&callback=GoogleMaps.initMap&v=weekly:212:276', name: 'InvalidValueError'}

Is there a better method of invoking the callback that I don't know about?

Score:0
de flag

You will need to ensure your library is loaded first, by creating it as a dependency of the first library:

delivery:
  version: 1.x
  js:
    js/delivery.js: {}
  dependencies:
  - core/jquery
  - core/drupalSettings

maps:
  js:
    'https://maps.googleapis.com/maps/api/js?key=AIzaSyCP9_LHyWKv821WTcLWZd8GcLLHIHvPPU0&callback=GoogleMaps.initMap&v=weekly':  { type: external, minified: true }
  dependencies:
  - order_form_webform_handler/delivery
Riley Lutz avatar
jm flag
Ok, I removed the GoogleMaps declaration line, but now it saying GoogleMaps is not defined. Where would be the best place to declare this variable if I need it to store this function?
Jaypan avatar
de flag
Sorry, I misunderstood your original post. I've updated my post.
Riley Lutz avatar
jm flag
It's all good. I edited the libraries.yml to what you posted, but it's still giving the "GoogleMaps.initMap is not a function" error from my original post.
Jaypan avatar
de flag
You have a couple options. Remove the anonymous wrapper and Drupal.behaviors, as `GoogleMaps.init()` will not exist until Drupal.behaviors is called, or, you can dynamically load the google maps script with JS instead of using libraries.
Riley Lutz avatar
jm flag
Oh man, so that was affecting it! Getting rid of the inner attached anon function fixed it, now the maps showing up, thank you!
Riley Lutz avatar
jm flag
Added my own answer summing up your solution, I'll accept it in a few days.
Score:0
gg flag

I've finally managed to hobble this together in a working manner for me:

my_module.libraries.yml:

my_module:
  version: 1.x
  js:
    js/my-module.js: {}
  dependencies:
    - core/jquery
    - my_module/maps
maps:
  js:
    //maps.googleapis.com/maps/api/js?key=[APIKEY]&callback=Function.prototype&libraries=places&v=weekly: { type: external, minified: true }

In the my_module.module file, I'm attaching the library in a hook_form_alter, but you may attach it in whatever function suits you...

$form['#attached']['library'][] = 'my_module/maps';
$form['#attached']['library'][] = 'my_module/my_module';

my-module.js:

// Initialize GoogleMaps object
let GoogleMaps = google.maps || {};

(function ($, Drupal, GoogleMaps) {

  Drupal.behaviors.myModuleMapsBehavior = {
    attach: function (context, settings) {

      GoogleMaps.fillInAddress = function () {
        console.log('fillInAddress');
        /* do something */
      };

      GoogleMaps.initMap = function () {
        console.log('initMap');
        GoogleMaps.fillInAddress();
        /* do something */
      };

      GoogleMaps.initMap();
    }
  };

})(jQuery, Drupal, GoogleMaps);

In the libraries file, I used the Function.prototype callback as described here: https://stackoverflow.com/a/75212692/1541757

In the first line of the js file, I had to change:

let GoogleMaps = GoogleMaps || {};

To ...

let GoogleMaps = google.maps || {};

I'm unsure if this is a Google API change or what, but this is working for me so far.

Score:-1
jm flag

Found the fix, the attach: function(....) wrapper line was affecting the visibility of the initMap function. Removing that cleared the error. Dynamically loading the script with JS would work as well, but did not get to a point where I tried testing that.

Riley Lutz avatar
jm flag
Could someone please tell me why this is being downvoted? Is my description of the fix not descriptive enough?
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.