1

I'm trying to display a google map on click with angular JS. But my function seems to be toggling the visibility based on a function call (via ng-show). This means that my trigger of the 'resize' event executes before the map div is actually visible so it doesn't work correctly.

$scope.mapVisible = false;
$scope.toggleMap = function() {
    $scope.myMap.panTo($scope.myMarkers[0].getPosition());
    $scope.mapVisible = !$scope.mapVisible;
    // this executes too soon. How to block until the div is really visible?
    google.maps.event.trigger($scope.myMap, 'resize');
}

<div ng-show="mapVisible">
   <!-- map here -->
</div>

So how can I block triggering the 'resize' event on my map until the div is truly visible?

2
  • It's not possible to execution while waiting on events in [browser] JavaScript. Use a callback (the question is then, just which one and how to attach it). Commented Mar 8, 2013 at 20:11
  • any idea how i can add a listener on the map div so i can trigger the event on the map when it becomes visible? Commented Mar 8, 2013 at 20:20

2 Answers 2

1
$scope.$watch("mapVisible", function (val) {
  if (val) {
    google.maps.event.trigger($scope.myMap, "resize");
  }
});

This would make sure the map is visible before triggering the event.
Angularjs handles two-way binding by doing dirty-checking. It basically means that the value being watched is compared to the one in previous cycle. Each cycle ($digest) starts to run when something happens which could possibly change any value in the scope. If there is a change in the value, it would be reflected after the cycle has completed.

Back to your problem, when you toggle the mapVisible property, the view does not update immediately. It waits for the cycle to end before redrawing the view. But you fire the resize event so early, when the map is still invisible, therefore rendering invalid.

$watch does indeed watch the property and the changes will be reflected in the next cycle of the change, which means the view would be updated by the time watcher function has been invoked. Putting the resize function here would hence solve your issue.

Sign up to request clarification or add additional context in comments.

5 Comments

well it does catch the event but my map is still a bit mangled. maybe this isn't what's causing the issue. i added a while loop counting to 5000 and then called the resize event and it didn't fit itself to the div correctly. so sort of right but not the fix in my case. good to know though thanks.
while loop counting the 5000 would be almost immediate in modern pc's. also it would block the current thread and nothing else would happen in js until it ends. you should use setTimeout(function () { /* body */ }, 5000) instead. (5000 = 5 seconds)
actually, triggering the resize manually on another event handler after the div is displayed does fix the map. Does a watch handler trigger when the value that's being watched changed, or is there a way to only call my function after ngShow has finished (without using a timer)?
To the best of my knowledge, it should be. However if not, you can always wrap the function body in a setTimeout with 50ms.
i've added a small timeout and it works locally. i'll test it when it's deployed. thanks.
0

I figured the easiest case is to use the $timeout service:

scope.$on "map:ui:shown", (event, args)->
    $timeout ->
      #use a delay because most of the time, the resizing should occur immediately after an angular cycle
      #like when an ng-show has been set to the True condition
      googleMaps.event.trigger(map, 'resize')
      map.fitBounds scope.bounds if scope.bounds

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.