2

So, I've posted on this elsewhere and I seem to either get half answers but they've gotten me closer to a solution but not over the finish line.

I'm trying to implement a custom Google Maps application that pulls data in from GeoJson views that I've made of an OpenLayers application that I've abandoned. The problem that I'm having is that if I follow the Drupal docs and wrap my code in a jQuery closure, then my Google Maps call back which is loaded in the global context is out of scope for the function.

I've written a simple module that loads a block of html with a map div, and then loads my google maps script externally in the footer. My map callback works when I load plain JS via my module, but not when wrapped in a closure and attached to a behavior. This poses two problems for me: 1) I can't use jQuery functions to get my data; 2) it's bad practice (as above). So, I guess my question comes down to how do I pull a callback on an externally loaded script into the scope of my Drupal behavior?

So loaded as plain JS this works:

 var map, alumLayer, chapterLayer, assocLayer, userLayer;
  function initMap() {
    map = new google.maps.Map(document.getElementById('json-map'), {
      zoom: 4,
      center: {lat: 38.43, lng: -90}
    });
 //ajax code to get map data here 
}

But this closure attempt doesn't:

    (function ($) {
Drupal.behaviors.gmap_json = {
attach : function (context, settings){
  var map, alumLayer, chapterLayer, assocLayer, userLayer;
  function initMap() {
    map = new google.maps.Map(document.getElementById('json-map'), {
      zoom: 4,
      center: {lat: 38.43, lng: -90}
    });
}
}
};  
  alert('it works');
}(jQuery));

So, I know that my problem here is scope, but I haven't yet found how to do this.Do I need to modify my callback trying to reference the behavior object somehow? Is there a way of mix and matching scoped jquery? Or best practices be damned, whatever gets it working?

2

As you've figured out, your problem is one of closures. In the code that is not working, you have initMap() enclosed in the anonymous function (function($){}(jQuery)). This means it's not part of the global scope, and therefore cannot be called from the global scope.

The solution to this is to set your function to be available globally. But of course, you don't want namespace collisions, which is the whole point of wrapping code in an anonymous function in the first place.

There is a happy medium here. You create a global variable, and add your callback to that from within your anonymous function:

// Initialize your global object. Set the value to itself (if it exists)
// or an empty object otherwise.
var GoogleMaps = GoogleMaps || {};

// Start your anonymous function.
(function($, Drupal, GoogleMaps) {
  Drupal.behaviors.someKey = {
    attach:function () {
      GoogleMaps.initMap = function () {
        // Initialize your map here
      };
    }
  };
})(jQuery, Drupal, GoogleMaps);

Use &callback=GoogleMaps.initMap in google maps api script embed.

You can also initialize your map from any other scripts using GoogleMaps.initMap()

  • Thanks, you have a blog post on this don’t you? That’s a great explanation as well. – nizz0k Mar 5 at 21:19
  • Going to test and accept tomorrow, thanks again. – nizz0k Mar 5 at 21:32
  • haven't had the time to dive in yet, but I wonder do I also need to change the reference to the callback when loading the Maps script? – nizz0k Mar 8 at 11:07
  • 2
    @nizz0k removing google, fixed my issue. – No Sssweat Mar 17 at 6:10
  • 1
    I've updated the code. You will want to put your function in Drupal.behaviors, as you are relying on the google object, which you will need to wait for page load to ensure is available. – Jaypan Mar 17 at 8:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.