I'm new to angular, and am having a problem changing the location inside of an event handler. The handler is for a marker positioned on a google map. I am using ng-map (which is pretty awesome).
Here's the code that creates the markers (this runs inside the success callback of an $http get):
for( i = 0; i < data.Pins.length; i++ )
{
var marker = new google.maps.Marker({
title: data.Pins[i].StreetAddress,
position: new google.maps.LatLng(data.Pins[i].Latitude,data.Pins[i].Longitude),
data: data.Pins[i],
index: i,
});
google.maps.event.addListener(marker, 'click', function(tgt) {
$scope.pinClicked(marker);
});
marker.setMap($scope.map);
$scope.markers.push(marker);
}
The event handler is very simple:
$scope.pinClicked = function(marker) {
if( marker.data.Homes.length == 1) $location.path("/home");
else $location.path("/unit");
};
When I click on a marker the handler executes, and the if/then/else statement is executed. However, the location does not change.
Is this because I'm outside the "context" for angular because I set up the event listener through google maps?
Additional Info
Thanx for the suggestion about using window.location. What I didn't mention earlier is that the map is part of a partial view, so I don't want to trigger a page reload -- I want angular to update the partial view based on a location change. Which I know it can do, because $location.path('/unit') works just fine outside of that event handler.
The problem is that the Google Maps event callback runs outside the Angular context. Calling $location.path("...")
is exactly correct (you should NOT use window.location
in an Angular app), but you must use the location service within a callback that's under Angular's control. That's not happening here. Consider this excerpt from your code:
$http.get(..., function() {
for (i = 0; i < data.Pins.length; i++) { // This is your FOR loop
...
google.maps.event.addListener(marker, 'click', function(tgt) {
$scope.pinClicked(marker);
});
The $http.get()
callback (your function) fires within the Angular context; when your function returns, Angular triggers a $digest cycle, which updates all bindings. It's the $digest cycle that will process any $location changes.
HOWEVER... The callback to google.maps.event.addListener
fires later, outside the Angular context. Angular won't see any scope changes or $location
changes you make within that callback (at least, not immediately—not until the next time a $digest cycle happens to run, whenever that is).
You need to wrap your call to $scope.pinClicked(marker)
within $scope.$apply
, like so:
google.maps.event.addListener(marker, 'click', function(tgt) {
$scope.$apply(function() {
$scope.pinClicked(marker);
});
});
By wrapping the call in $scope.$apply
, you've essentially told Angular, "Hey, run the code in this function, and then kick off a $digest cycle."