-
-
Save benmj/6380466 to your computer and use it in GitHub Desktop.
/*global angular: true, google: true, _ : true */ | |
'use strict'; | |
angular.module('geocoder', ['ngStorage']).factory('Geocoder', function ($localStorage, $q, $timeout) { | |
var locations = $localStorage.locations ? JSON.parse($localStorage.locations) : {}; | |
var queue = []; | |
// Amount of time (in milliseconds) to pause between each trip to the | |
// Geocoding API, which places limits on frequency. | |
var queryPause = 250; | |
/** | |
* executeNext() - execute the next function in the queue. | |
* If a result is returned, fulfill the promise. | |
* If we get an error, reject the promise (with message). | |
* If we receive OVER_QUERY_LIMIT, increase interval and try again. | |
*/ | |
var executeNext = function () { | |
var task = queue[0], | |
geocoder = new google.maps.Geocoder(); | |
geocoder.geocode({ address : task.address }, function (result, status) { | |
if (status === google.maps.GeocoderStatus.OK) { | |
var latLng = { | |
lat: result[0].geometry.location.lat(), | |
lng: result[0].geometry.location.lng() | |
}; | |
queue.shift(); | |
locations[task.address] = latLng; | |
$localStorage.locations = JSON.stringify(locations); | |
task.d.resolve(latLng); | |
if (queue.length) { | |
$timeout(executeNext, queryPause); | |
} | |
} else if (status === google.maps.GeocoderStatus.ZERO_RESULTS) { | |
queue.shift(); | |
task.d.reject({ | |
type: 'zero', | |
message: 'Zero results for geocoding address ' + task.address | |
}); | |
} else if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) { | |
queryPause += 250; | |
$timeout(executeNext, queryPause); | |
} else if (status === google.maps.GeocoderStatus.REQUEST_DENIED) { | |
queue.shift(); | |
task.d.reject({ | |
type: 'denied', | |
message: 'Request denied for geocoding address ' + task.address | |
}); | |
} else if (status === google.maps.GeocoderStatus.INVALID_REQUEST) { | |
queue.shift(); | |
task.d.reject({ | |
type: 'invalid', | |
message: 'Invalid request for geocoding address ' + task.address | |
}); | |
} | |
}); | |
}; | |
return { | |
latLngForAddress : function (address) { | |
var d = $q.defer(); | |
if (_.has(locations, address)) { | |
$timeout(function () { | |
d.resolve(locations[address]); | |
}); | |
} else { | |
queue.push({ | |
address: address, | |
d: d | |
}); | |
if (queue.length === 1) { | |
executeNext(); | |
} | |
} | |
return d.promise; | |
} | |
}; | |
}); |
and could you provide a example for the usage?
Great service, but does not survive minification. Can you change your gist like so:
angular.module('geocoder', ['ngStorage']).factory('Geocoder', ['$localStorage', '$q', '$timeout', function ($localStorage, $q, $timeout) {
and
} ]);
at the last line
How to use (in Coffeescript):
$scope.geocode = (address) ->
p = Geocoder.latLngForAddress address
fnSuccess = (latLng) ->
$scope.data.latitude = latLng.lat
$scope.data.longitude = latLng.lng
fnError= () ->
# not found somewhere.
console.log "ERROR"
p.then fnSuccess,fnError
thanks for the gist
similar way for getting latlng with location api and reverse geocoding
https://gist.github.com/suras/8196789
I'd like to see an example of this is used. It looks really promising!
Thanks for sharing. Very helpful.
BUG REPORT: you are missing a call to "$rootScope.$apply()" at line 62. When the resultCallback for "geocoder.geocode( resultCallback )" is invoked it is not part of the angular $digest cycle. Therefore, you need to explicitly call "$rootScope.$apply()" (and of course include $rootScope in your dependencies).
Once you do this then your code works like a charm!
Thank you.
BUG REPORT: Additionally, executeNext() is not being called if the response type is zero results, request denied or invalid result.
I've forked the gist to make the fixes. I've also simplified the query pause logic (didn't like the query pause timeout creeping upwards and I wanted to be more aggressive with retries). Link below:
Thank you for this gist. I took the liberty of forking it and modifying it to work with the angular-google-maps
library.
_.has(locations, address) can be replaced with Object.keys(locations).indexOf(address) > -1
This can remove the _ dependency
@benmj thanks for posting this gist, and @david-meza, thanks for modifying it to work with angular-google-maps
. I'm using angular-local-storage
in my project, so I made a fork that works with it instead of ngStorage.
Great service, When I try to integrate, I get the below error.
TypeError: Cannot read property 'geocode' of undefined
Could you please suggest me a fix?
Thanks
Is there a way to do this without
_
?