0

I have an issue where my Google Map does not display 80% of the time. It seems to be a situation where my map has not completely rendered by the time the rest of my data has been populated in my Angular view.

How can I force my map to load?

I have done some research, and I have found this answer on a related questions, but I am not sure how and if I can implement something like this:

This was bothering me for a while with GMaps v3. I found a way to do it like this:

google.maps.event.addListenerOnce(map, 'idle', function(){
    // do something only the first time the map is loaded
});

The "idle" event is triggered when the map goes to idle state - everything loaded (or failed to load). I found it to be more reliable then tilesloaded/bounds_changed and using addListenerOnce method the code in the closure is executed the first time "idle" is fired and then the event is detached.

Link: How can I check whether Google Maps is fully loaded?

This is my current setup:

1. My Google Maps API link and key is in my index.html file:

<script src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXXXXXXXXX"></script>

2. I use the following as my Angular Directive:

'use strict';

angular.module('portalDashboardApp')
  .directive('ogGoogleMap', function ($http, $q) {
      return {
          restrict: 'E',
          scope: {
              twitter: '=',
              instagram: '='
          },
          template: '<div id="gmaps"></div>',
          replace: true,
          link: function (scope, element, attrs) {

              var map, infoWindow;
              var markers = [];

              // map config
              var mapOptions = {
                  center: new google.maps.LatLng(-0.013026, 21.333860),
                  zoom: 3,
                  mapTypeId: google.maps.MapTypeId.ROADMAP
              };

              // init the map
              function initMap() {
                  if (map === void 0) {
                      map = new google.maps.Map(element[0], mapOptions);
                  }
              }

              // place a marker
              function setMarker(map, position, title, content, icon) {

                  if (icon === 'IN') {
                      icon = 'images/instagramMarker.png';
                  }
                  else {
                      icon = 'images/twitterMarker.png';
                  }

                  var marker;
                  var markerOptions = {
                      position: position,
                      map: map,
                      title: title,
                      icon: icon
                  };

                  marker = new google.maps.Marker(markerOptions);
                  markers.push(marker); // add marker to array

                  google.maps.event.addListener(marker, 'click', function () {
                      // close window if not undefined
                      if (infoWindow !== void 0) {
                          infoWindow.close();
                      }
                      // create new window
                      var infoWindowOptions = {
                          content: content
                      };
                      infoWindow = new google.maps.InfoWindow(infoWindowOptions);
                      infoWindow.open(map, marker);
                  });
              }

              function deleteCurrentMarkers() {
                  for (var i = 0; i < markers.length; i++) {
                      markers[i].setMap(null);
                  }
                  markers = [];
              }

              scope.$watch('instagram', function () {
                  deleteCurrentMarkers();
                  populateMarkers(scope.twitter, 'TW');
                  populateMarkers(scope.instagram, 'IN');
              });

              // show the map and place some markers
              initMap();

              function populateMarkers(locationArray, type) {

                  angular.forEach(locationArray, function (location) {

                      setMarker(map, new google.maps.LatLng(location[0], location[1]), '', '', type);

                  });

              }

          }
      };
  });

3. I use the following simple method of assigning my map data in my Angular Controller:

First I retrieve my data:

function pullSocialData() {

    SocialMediaUserService.getKeywordProfileID().then(function (keywordProfileID) {

        GetFusionDataService.getItems(getRequestURL(keywordProfileID))
          .success(function (data) {

              formatDataAccordingToLocation(data);

          })
          .error(function (error, status) {
              handleDataRetrievalError(error, status);
          });

    });
}

The I assign my data:

function formatDataAccordingToLocation(data) {
    $scope.twitterLocations = data.lat_longs_twitter;
    $scope.instagramLocations = data.lat_longs_instagram;
}

This is what my data from the API looks like:

lat_longs_twitter: [
    [
    -25.77109,
    28.09264
    ],
    [
    -26.1078272,
    28.2229014
    ]
]

4. My HTML map div:

<div ng-show="!demographics.showDemographicsGraph">
    <og-google-map twitter="twitterLocations" instagram="instagramLocations"></og-google-map>
</div>

When my map loads properly, it looks like this:

enter image description here

When it doesn't load properly it looks like this:

enter image description here

Thank you in advance!

Community
  • 1
  • 1
onmyway
  • 1,435
  • 3
  • 29
  • 53
  • I would call `initMap()` inside the map load callback so you know that it has been properly loaded – Dario Jan 30 '17 at 08:25
  • @Dario May I ask that you perhaps clarify or give an example? I am not too sure from where to call the `initMap()` method. I have added all aspects related to the maps to my question. Thank you! – onmyway Jan 30 '17 at 08:44

2 Answers2

0

In your directive link function, try to move initMap inside the map idle callback:

google.maps.event.addListenerOnce(map, 'idle', function(){ 
   // show the map and place some markers
   initMap();
});
Dario
  • 6,152
  • 9
  • 39
  • 50
  • I think I might be doing something wrong. I have inserted the map `idle` callback in a number of places in my link function, and put breakpoints on each `initMap()` call in these callbacks, but the breakpoints are never hit. Any suggestions? – onmyway Jan 30 '17 at 10:31
  • 1
    Which version of google map are you using? Try to use `google.maps.event.addListener` (without `Once`) – Dario Jan 30 '17 at 10:47
  • Just some feedback; I have tried a number of different proposed solutions, but none worked. I always got the same result; whatever i used as validation, equated to true, and the script would run and the map didn't load. I tried `if (google && google.maps)`, I tried `google.maps.event.addListenerOnce(map, 'idle', function (){}`, I tried `if (typeof google === 'object' && typeof google.maps === 'object'){}`, `google.maps.event.addListenerOnce(map, 'tilesloaded', function (){}` and some other variations. I finally got it to work, by making the following change in `scope.$watch` *see answer – onmyway Jan 31 '17 at 09:21
0

To make my map load, I added some validation to check whether my data has returned before initializing the map. I also added a timeOut for good measure, to give the map more time to render.

I made the following change in my Angular Directive:

scope.$watch('instagram', function () {
  if (scope.twitter != undefined || scope.instagram != undefined) {
      initMap();
      setTimeout(function () {
          deleteCurrentMarkers();
          populateMarkers(scope.twitter, 'TW');
          populateMarkers(scope.instagram, 'IN');
      }, 3000);
  }
});
onmyway
  • 1,435
  • 3
  • 29
  • 53