AngularJS Geolocation data update - javascript

I'm doing a mobile app using AngularJS.
What I'm trying to achieve is to update the geolocation data as soon as I turn on the GPS. How do I achieve this? The problem I'm facing is, in order for the data to be updated I have to navigate to other page. These are the codes. I'm sharing data from one controller to the other.
.factory('sharedProperties', function () {
var coordinates = {};
var getC = function () {
return coordinates;
};
var setC = function (value) {
coordinates = value;
return coordinates;
};
return {
getCoords: getC,
setCoords: setC
};
})
First Controller
.controller('MessageController', ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
var nObj = sharedProperties.getCoords();
console.log(nObj);
$scope.message = "This is my location: " + nObj.lat + ", " + nObj.lng + ". I'm around " + nObj.acc + " meters from point.";
}])
Second Controller
.controller("mainController", ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
$scope.lat = "0";
$scope.lng = "0";
$scope.accuracy = "0";
$scope.error = "";
$scope.model = {
myMap: undefined
};
$scope.myMarkers = [];
$scope.showResult = function () {
return $scope.error == "";
}
$scope.mapOptions = {
center: new google.maps.LatLng($scope.lat, $scope.lng),
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true
};
$scope.showPosition = function (position) {
$scope.lat = position.coords.latitude;
$scope.lng = position.coords.longitude;
$scope.accuracy = position.coords.accuracy;
$scope.$apply();
sharedProperties.setCoords({
'lat': position.coords.latitude,
'lng': position.coords.longitude,
'acc': position.coords.accuracy
});
var latlng = new google.maps.LatLng($scope.lat, $scope.lng);
$scope.model.myMap.setCenter(latlng);
$scope.myMarkers.push(new google.maps.Marker({
map: $scope.model.myMap,
position: latlng,
title: 'You are here'
}));
}
$scope.showMarkerInfo = function (marker) {
$scope.myInfoWindow.open($scope.model.myMap, marker);
};
$scope.showError = function (error) {
switch (error.code) {
case error.PERMISSION_DENIED:
$scope.error = "User denied the request for Geolocation."
break;
case error.POSITION_UNAVAILABLE:
$scope.error = "Location information is unavailable."
break;
case error.TIMEOUT:
$scope.error = "The request to get user location timed out."
break;
case error.UNKNOWN_ERROR:
$scope.error = "An unknown error occurred."
break;
}
$scope.$apply();
}
$scope.getLocation = function () {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition($scope.showPosition, $scope.showError,
{ enableHighAccuracy: true});
} else {
$scope.error = "Geolocation is not supported by this browser.";
}
}
$scope.getLocation();
}])
EDIT:
Somehow I managed to get it to work like this.
.controller('MessageController', ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
$scope.getLoc = function () {
var nObj = sharedProperties.getCoords();
console.log(nObj);
var numbers = [nObj.lat, nObj.lng, nObj.acc];
return "This is my location: " + numbers[0].toFixed(6) + ", " + numbers[1].toFixed(6) + ". I'm around " + numbers[2].toFixed(0) + " meters from point.";
}])
And in the view, I put it like this.
<textarea style="width: 100%; height: 183px;" placeholder="Message">{{getLoc()}}</textarea>
but it displays the {{getLoc()}} in the textarea. Is there anyway that I can hide this and show only when it gets the data?

You may use ng-bind-html
So it will be like
<textarea style="width: 100%; height: 183px;" placeholder="Message" ng-bind-html="getLoc()"></textarea>

Related

Angularjs: Google Map Api - Google is not defined

I'm working on an angularjs single-page application, and I'm trying to build a mapping system for the application. The map is loading fine, however whenever I attempt to use the geocode functionality, I get the error referenceError: Google is not defined.
Map controller
(function () {
'use strict';
angular
.module('CityWits')
.controller('mapCtrl', mapCtrl);
mapCtrl.$inject = ['$scope', '$http', 'mapApi', '$q'];
function mapCtrl($scope, $http, mapApi, $q){
var vm = this;
vm.setQuery = setQuery;
// todo: Switch this out with deals that are loaded depending on the radius of the map
getBranches();
function setQuery(query) {
console.log("business deal filter controller : query=" + query);
vm.query = query;
vm.focus = false;
}
function getBranches(){
$http.get('app/cwitsTestData/branchData.json').then(function(data){
vm.branches = sortBranches(data.data.branches);
$scope.$broadcast("branchesSorted", vm.branches);
});
}
}
function sortBranches(branches){
var locations, address, text;
locations = [];
for(var branch in branches){
address = branches[branch].address;
text = address.street_line1 + " " + address.city+ " " +address.state;
locations.push(text);
}
return locations;
}
})();
Here's the google factory I wrote to handle the api:
(function() {
'use strict';
angular
.module('CityWits')
.factory('mapApi', mapApi);
function mapApi () {
var mapApi = {}
var markers = [];
var geocoder;
var service;
mapApi.geocode = geocode;
mapApi.marker = marker;
mapApi.distance = distance;
return mapApi;
function geocode (addresses){
geocoder = new google.maps.Geocoder();
var coords = [];
if(geocoder){
for(var i in addresses){
geocoder.geocode( { 'address': addresses[i]}, function(results, status) {
if (status === 'OK') {
coords.push(results[0].geometry.location);
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
});
}
}
}
function distance(start, end, method="DRIVING"){
service = new google.maps.DistanceMatrixService;
service.getDistanceMatrix({
origins: start,
destinations: end,
travelMode: method
}, function (status, response){
if(status ==! "OK"){
console.log("Error: "+status);
} else {
console.log("distance measured");
var result = {};
for(var i in response.rows){
result = response.rows[i].element;
}
return result;
}
});
}
function marker(positions, json){
if(markers.length > 0){
for(o in markers){
markers[o].setMap(null);
}
}
for(x in positions){
}
}
}
})();
And lastly this is the directive that initiates the api:
(function () {
'use strict';
angular
.module('CityWits')
.directive('dealMap', dealMap);
dealMap.$inject = ['$timeout', '$http', 'mapApi'];
function dealMap($timeout, $http, mapApi){
var directive = {
link: link,
templateUrl: 'app/map/map.directive.html',
scope: {
deals: '=',
branches: '='
},
restrict: 'EA'
};
return directive;
function link(scope, element, attrs) {
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.defer = true;
script.src = "https://maps.googleapis.com/maps/api/js?key=AIzaSyB4RaOArTNm9C7crfutMVc0KkWIoQG-ZE0";
document.body.appendChild(script);
$timeout(function(){
scope.initialize();
}, 500);
// todo: Do stuff after deals are loaded based on map radius
scope.$on('branchesSorted', function(event, data) {
console.log('deals loaded');
console.log(data);
var points = mapApi.geocode(data);
console.log(points);
});
scope.initialize = function() {
scope.mapOptions = {
zoom: 8,
center: new google.maps.LatLng(22.649907498685803, 88.36255413913727)
};
scope.map = new google.maps.Map(document.getElementById('map'), scope.mapOptions);
};
console.log(scope);
}
}
})();
Apparently this error occurs since the Google Maps API is not yet loaded.
The moment when the data is getting loaded:
$http.get('app/cwitsTestData/branchData.json').then(function(data){
vm.branches = sortBranches(data.data.branches);
$scope.$broadcast("branchesSorted", vm.branches);
});
and afterwards once Geocoder is utilized, there is no any guarantee that Google Maps API is already loaded at that moment:
scope.$on('branchesSorted', function(event, data) {
console.log('deals loaded');
console.log(data);
var points = mapApi.geocode(data); //<--Google Maps API could be still not loaded at that moment
console.log(points);
});
since Google Maps library is getting loaded asynchronously in your example like this:
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.defer = true;
script.src = "https://maps.googleapis.com/maps/api/js?key=AIzaSyB4RaOArTNm9C7crfutMVc0KkWIoQG-ZE0";
document.body.appendChild(script);
I would propose the following solution instead.
Let's introduce the following service to load Google Maps API, create the map and notify once it is ready:
.factory('googleMapsApi', function ($rootScope,$window, $q) {
return {
load: function (key) {
var deferred = $q.defer()
if ($window.google && $window.google.maps) {
deferred.resolve($window.google);
}
else {
var url = 'https://maps.googleapis.com/maps/api/js?callback=googleMapsLoad';
if (key) url += "&key=" + key;
var script = document.createElement('script');
script.type = 'text/javascript'
script.src = url;
$window.googleMapsLoad = function () {
deferred.resolve($window.google);
}
document.body.appendChild(script);
}
return deferred.promise;
},
createMap : function(scope,id,options){
var mapObject = new google.maps.Map(document.getElementById(id), options);
scope.$emit('google-maps-loaded',mapObject);
},
onMapReady : function(scope, ready){
var handler = $rootScope.$on('google-maps-loaded', function(evnt,data){ return ready(data);});
scope.$on('$destroy', handler);
}
}
})
Then the map could be created like this via link function of directive:
link: function (scope, element, attributes) {
googleMapsApi.load(scope.key)
.then(function () {
var mapOptions = {
center: scope.center,
zoom: scope.zoom,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
googleMapsApi.createMap(scope,attributes.id,mapOptions);
});
}
and data is loaded in controller like this:
.controller('MyCtrl', function ($scope, googleMapsApi) {
googleMapsApi.onMapReady($scope, function(mapInst) {
console.log('Google Map is ready');
mapInst.data.loadGeoJson('https://storage.googleapis.com/mapsdevsite/json/google.json');
});
});
JSFiddle example

Is there an alternative to ng-init to execute all the times?

First of all. I'm sorry if my explanation is confused. If you see the code below which is my index.html from my Ionic project. It executes ok in the first time, but as soon as I add a new word and in the ng-repeat it has more than 1 word.. the function inside the ng-init execute just one time, just for the last word (string) added. Not for all again.
So, the ng-init is executing just one time... not for all the words. Is there any alternative for ng-init?
<div class="buttons">
<button ng-click="vm.showAddBirthdayModal()" class="button button-icon icon ion-android-add">
</button>
</div>
<ion-item ng-repeat="b in vm.birthdays" ng-click="vm.showEditBirthdayModal(b)">
<div style="float: left">
<ion-text>{{b.Name}} : </ion-text>
<ion-text ng-init="getTwitter(this.b.Name)">{{twitts[b.Name].count}}</ion-text>
</div>
</ion-item>
This is my getTwitter:
$scope.getTwitter = function(hashtag) {
$scope.twitts = {};
var posOptions = {timeout: 10000, enableHighAccuracy: false};
$cordovaGeolocation.getCurrentPosition(posOptions)
.then(function (position) {
var lat = position.coords.latitude;
$scope.lat = lat;
var long = position.coords.longitude;
$scope.long = long;
$ionicLoading.show();
$http.get('https://twitter.net/api/twitter/count?lat=' + lat + '&lng=' + long + '&keywords=' + hashtag + '')
.success(function(twitts) {
$scope.twitts[hashtag] = twitts;
//console.log('Twitts: '+$scope.twitts);
$ionicLoading.hide();
})
.error(function(erro) {
//$scope.twitts = twitts;
console.log(erro);
})
.finally(function() {
// Stop the ion-refresher from spinning
$scope.$broadcast('scroll.refreshComplete');
});
console.log('Latitude: '+ lat + ' Longitude: ' + long)
}, function(err) {
console.log(err)
});
}
First of all you shouldn't apply this code in your controller but in a service. You could do something like:
Service
.service('tweetSrv', function ($q, $http, $cordovaGeolocation, $ionicLoading) {
var getTweets = function (twitts) {
var posOptions = {
timeout: 10000,
enableHighAccuracy: false
};
return $q(function (resolve, reject) {
$cordovaGeolocation.getCurrentPosition(posOptions).then(function (position) {
var lat = position.coords.latitude;
// $scope.lat = lat;
var long = position.coords.longitude;
// $scope.long = long;
$ionicLoading.show();
$http.get('https://twitter.net/api/twitter/count?lat=' + lat + '&lng=' + long + '&keywords=' + hashtag + '')
.then(function (response) {
resolve(response);
//console.log('Twitts: '+$scope.twitts);
$ionicLoading.hide();
}, function () {
reject("Something's wrong");
})
console.log('Latitude: ' + lat + ' Longitude: ' + long);
}, function (err) {
console.log(err)
})
})
}
return {
getTweets: getTweets
}
})
And in your controller
var birthdaysLength = $scope.birthdays.length();
var i = 0;
var getBirthdaysTweets = function (name, index) {
tweetSrv.getTweets(name).then(function (tweetsCount) {
$scope.birthdays[index].tweets = tweetsCount;
index++;
if (index < birthdaysLength)
getBirthdaysTweets($scope.birthdays[index].name, index);
else {
$scope.$broadcast('scroll.refreshComplete');
console.log("Done. I've loaded tweets for all birthdays");
}
}, function (errorString) {
console.log(errorString);
})
}
getBirthdaysTweets($scope.birthdays[i].name, i);

Map does not load centered when doing first search

Can anyone tell me why the map does not load centered the first time it loads? It works fine when I do a second search, but never loads up correctly the first time.
src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"
var directionsDisplay;
var directionsService;
var geocoder;
var currentAddress = 'placeholder';
var tabCount = 0;
var altRouteCount = 0;
var savedRoutes;
$(document).ready(function(){
$('#message-container').hide (0);
document.getElementById('sidebar').className = 'sidebar-hidden';
// Keeps form pointAB from refreshing the page.
$('#pointAB').on('submit', function (e) {
e.preventDefault();
});
$('#tabs').tab();
$('#tabs a').click( function (e) {
e.preventDefault();
$(this).tab('show');
});
$('#sidebar #togglebtn').click(toggleSidebar);
$('#deletes').click(deleteTabs);
$('#routeChange').click(function () {
var index = $('#routeChange').data('route');
index = (index+1)%altRouteCount;
deleteTabs();
printRoute (savedRoutes, index);
$('#routeChange').data('route', index);
});
// Call Google Direction
directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
// Google Autocomplete
var start_input = document.getElementById('start');
var end_input = document.getElementById('end');
var bounds = new google.maps.LatLngBounds(
new google.maps.LatLng(40.532980, -74.118551),
new google.maps.LatLng(40.895218, -73.735403)
);
// Bounds right now only restrict country
var start_autocomplete = new google.maps.places.Autocomplete((start_input),{
// bounds: {sw:new google.maps.LatLng(40.895218, -73.735403), ne:new google.maps.LatLng(40.532980, -74.118551)},
componentRestrictions: {country: 'us'}
}
);
var end_autocomplete = new google.maps.places.Autocomplete((end_input),{
// bounds: {sw:new google.maps.LatLng(40.895218, -73.735403), ne:new google.maps.LatLng(40.532980, -74.118551)},
componentRestrictions: {country: 'us'}
}
);
start_autocomplete.setBounds(bounds);
end_autocomplete.setBounds(bounds);
// Initial map
function initialize() {
var map;
var pos;
// Default pos for map will be center of Manhattan
if(!pos){
pos = new google.maps.LatLng(40.784148400000000000, -73.966140699999980000);
}
var mapOptions = {
zoom: 13
};
getAddress();
// Draw Map
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
map.setCenter(pos);
// Google Direction text route
directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById('directions-panel'));
//Needed to resize maps
google.maps.event.addDomListener (map, 'idle', function(){
google.maps.event.trigger (map, 'resize');
});
}
// Load Map
google.maps.event.addDomListener(window, 'load', initialize);
});
/************************************************
Site Navigational Elements
************************************************/
function toggleSidebar() {
var state = $('#sidebar').data('toggle');
if (state == 'hidden') {
document.getElementById('sidebar').className = "sidebar-appear";
$('#sidebar').data('toggle', 'shown');
}
else if (state == 'shown') {
document.getElementById('sidebar').className = "sidebar-hidden";
$('#sidebar').data('toggle', 'hidden');
}
};
function nextSlide() {
$('#navCarousel').carousel('next');
};
function prevSlide(){
$('#navCarousel').carousel('prev');
};
/************************************************
UI Messages
************************************************/
function hideMessage(){
$('#init-message').hide(1000);
};
function pushMessage (messageType, message) {
$('#message-container').hide (0);
if (messageType == 'error') {
document.getElementById('message-container').className = "alert alert-danger";
document.getElementById('icon').className = "glyphicon glyphicon-remove-sign";
}
else if (messageType == 'success') {
document.getElementById('message-container').className = "alert alert-success";
document.getElementById('icon').className = "glyphicon glyphicon-ok-sign";
}
else if (messageType == 'warn') {
document.getElementById('message-container').className = "alert alert-warning";
document.getElementById('icon').className = "glyphicon glyphicon-exclaimation-sign";
}
else {
//Congrats. Senpai has noticed your ability to break shit. Rejoice.
console.error ("Please check your messageType.")
}
$('#message').text(message);
$('#message-container').show (1000);
};
/************************************************
Information Retrieval
************************************************/
// Get current location button function
function getAddress(callback){
geocoder = new google.maps.Geocoder();
// If geolocation available, get position
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(successCallback, errorCallback, {timeout:60000,maximumAge:60000});
}
//Else, browser doesn't support geolocaiton
else {
pushMessage ('error', 'Your browser doesn\'t support geolocation.');
console.log("Browser doesn't support geolocaiton");
}
// Optional callback
if (callback){
callback();
}
};
function successCallback(position){
var pos = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
//Reverse geocoding for current location
geocoder.geocode({'latLng': pos}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results.length != 0) {
currentAddress = results[0].formatted_address;
} else {
alert('No results found');
}
} else {
alert('Geocoder failed due to: ' + status);
}
});
};
function errorCallback(){
};
fillAddress = function() {
if (currentAddress != 'placeholder') {
$('#start').val (currentAddress);
pushMessage ('success', "Got your current location!");
}
else {
pushMessage ('warn', 'Please share your location to use this feature.');
}
};
// Set route and request direction result
function calcRoute() {
var start = document.getElementById('start').value;
var end = document.getElementById('end').value;
if (start == '' && end == '') {
pushMessage ('error', "Please fill in your current location and destination.");
start='';
end='';
return;
}
else if (start == '') {
pushMessage ('error', "Please fill in your current location.");
start='';
end='';
return;
}
else if (end == '') {
pushMessage ('error', "Please fill in your destination.");
start='';
end='';
return;
}
else {
start += ' new york city';
end += ' new york city';
}
var request = {
origin: start,
destination: end,
provideRouteAlternatives: true,
travelMode: google.maps.TravelMode.TRANSIT
};
deleteTabs();
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
altRouteCount = response.routes.length;
savedRoutes = response;
printRoute (savedRoutes, 0);
//Move to next slide when directions have been retrieved.
$('#navCarousel').carousel('next');
//Disable loading icon pseudocode.
//$('#loadingIcon').hide(300);
savedRoutes = response;
}
else {
//If DirectionsStatus.NOT_FOUND
//or DirectionsStatus.ZERO_RESULTS
pushMessage ('error', 'No directions found.');
}
});
};
function printRoute (routeObj, routeNo) {
// Get route object
var thisRoute = routeObj.routes[routeNo].legs[0];
for (var i = 0; i < thisRoute.steps.length; i++) {
// Find all possible transit
if (typeof thisRoute.steps[i].transit != 'undefined'
&& thisRoute.steps[i].transit.line.vehicle.type == "SUBWAY") {
trainTab (thisRoute.steps[i]);
}
}
}
//Get details from Maps API json object
function getTransitDetail(obj, tabNo){
var parent='';
if (tabNo) {
parent='div#tab'+tabNo+' ';
}
$(parent+'#train').text(obj.transit.line.short_name + " Train");
$(parent+'#train-stop-depart').text(obj.transit.departure_stop.name);
$(parent+'#train-stop-end').text(obj.transit.arrival_stop.name);
$(parent+'#num-stop').text(obj.transit.num_stops + " Stops");
$(parent+'#arrival_time').text(obj.transit.arrival_time.text);
$(parent+'#departure_time').text(obj.transit.departure_time.text);
$(parent+'#distance').text(obj.distance.text);
$(parent+'#duration').text(obj.duration.text);
};
// Get current time from device
function getTime(){
var currentdate = new Date();
var datetime = currentdate.getDate() + "/"
+ (currentdate.getMonth()+1) + "/"
+ currentdate.getFullYear() + " # "
+ currentdate.getHours() + ":"
+ currentdate.getMinutes() + ":"
+ currentdate.getSeconds();
return datetime;
};
function makeNewTab() {
var prevTab = 'tab' + tabCount;
tabCount++;
var newTab = 'tab' + tabCount;
console.log ('New Tab.');
//Adds tab to nav bar
$('#routeChange').before('<li>TAG LABEL</li>');
//Adds contents of tab
$('div.tab-content #'+prevTab).after('<div id="'+newTab+'"></div>');
$('#'+newTab).addClass("tab-pane");
};
function deleteTabs() {
var thisTab;
while (tabCount >= 1) {
thisTab = 'tab' + tabCount;
//Remove tab from nav bar
$('ul#tabs li a[href="#'+thisTab+'"]').remove();
//Remove contents of tab
$('#'+thisTab).remove();
tabCount--;
}
tabCount = 1;
$('#tabs a:first').tab('show');
};
function trainTab (obj) {
makeNewTab();
$('ul#tabs li a[href="#tab'+tabCount+'"]').text(obj.transit.line.short_name);
$('#tab'+tabCount).append (
'<div id="station-info" class="col-xs-11 col-xs-height col-sm-12 col-sm-height">\
<p>Station Info:</p>\
<p id="train"></p>\
<p id="train-stop-depart"></p>\
<p id="train-stop-end"></p>\
<p id="num-stop"></p>\
<p id="arrival_time"></p>\
<p id="departure_time"></p>\
<p id="distance"></p>\
<p id="duration"></p>\
<!-- <%= link_to "an article", #station%> -->\
</div>');
getTransitDetail (obj, tabCount);
};
Is it because of the order of my code? I tried playing around with the order and could not find a solution. Any help would be appreciated. Thanks in advance!

Object property is not created inside a factory member function

I have an object inside an Angular.js factory:
angular.module('myapp')
.factory('geoLocationService', function () {
var geoLocationObj = {};
var geocoder = new google.maps.Geocoder();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(_successFunction, _errorFunction);
}
function _successFunction(position) {
var lat = position.coords.latitude;
var lng = position.coords.longitude;
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({'latLng': latlng}, function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
if (results[2]) {
geoLocationObj.resultCity = results[2].formatted_address;
alert(geoLocationObj.resultCity);
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
return geoLocationObj;
});
This works alert(geoLocationObj.resultCity); and alerts in property value
But
console.log(geoLocationObj);
does not log the propety geoLocationObj.resultCity
I am trying to use geoLocationObj.resultCity outside the Factory in my controller but it is not there.
I have in my controller:
.controller('IndexCtrl', function ($scope, geoLocationService) {
var geoLocationService = geoLocationService;
console.log(geoLocationService);
geoLocationService is an empty Object
I cannot figure out why this is happening.
Can you help me with this?
The problem in your code is that your object is initialize in the callback (_successFunction) that means that the returned object is still empty because the _successFunction hasn't been called.
You should return a promise using $q and call .then() in your controller.
angular.module('myapp')
.factory('geoLocationService', ['$q', function ($q) {
var geoLocationObj = {};
var deferred = $q.defer();
var geocoder = new google.maps.Geocoder();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(_successFunction, _errorFunction);
}
function _successFunction(position) {
var lat = position.coords.latitude;
var lng = position.coords.longitude;
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({'latLng': latlng}, function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
if (results[2]) {
deferred.resolve(results[2].formatted_address);
alert(geoLocationObj.resultCity);
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
return deferred.promise;
})];
And in your controller
.controller('IndexCtrl', function ($scope, geoLocationService) {
geoLocationService.then(function(geoLocObj){
console.log(geoLocObj); Here your object has been resolved
});
Your factory should return something like this
angular.module('myapp')
.factory('geoLocationService', function() {
return{
geoLocationObj:function(){
var geocoder = new google.maps.Geocoder();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(_successFunction, _errorFunction);
}
function _successFunction(position) {
var lat = position.coords.latitude;
var lng = position.coords.longitude;
var latlng = new google.maps.LatLng(lat, lng);
geocoder.geocode({'latLng': latlng}, function (results, status) {
if (status === google.maps.GeocoderStatus.OK) {
if (results[2]) {
geoLocationObj.resultCity = results[2].formatted_address;
alert(geoLocationObj.resultCity);
} else {
alert("No results found");
}
} else {
alert("Geocoder failed due to: " + status);
}
});
}
return geoLocationObj
}
}
});
You can call in your controller like this
angular.module('myapp', [])
.controller('IndexCtrl', function ($scope, geoLocationService) {
var promise = geoLocationService.geoLocationObj()
promise.then(function(success){
console.log("me "+success);
},function(error){
console.log("They eat all my candies :" +error)
})
});
You can play it here in Js bin
PS. You need to include your google map libs

Google Maps AngularJS with multiple addresses

I have an application that uses an AngularJS service and using Angular-Google-Maps and I do get multiple markers on my map but I can't get the click on each marker to work. The only marker that allows a click is the last one which doesn't allow me to close it after opening the window or if I only have one address the marker works as expected. I think I'm close but can't figure out what I might be missing to have the click on the markers work for all of them. Any ideas on what I'm missing or need to do differently?
Here is the markup on my page.
<div ng-app="myMapApp" ng-controller="mapController">
<ui-gmap-google-map center='map.center' zoom='map.zoom' options="options">
<ui-gmap-markers models="directoryMarkers" coords="'self'" icon="'icon'" click="'onClick'">
<ui-gmap-windows show="show">
<div ng-non-bindable>{{organization}}</div>
</ui-gmap-window>
</ui-gmap-markers>
</ui-gmap-google-map>
</div>
The code in myMapApp.js
var app = angular.module("myMapApp", ['uiGmapgoogle-maps', 'ngStorage']);
The code in mapController.js
app.controller('mapController', function ($scope, Geocoder) {
$scope.map = { center: { latitude: 45, longitude: -73 }, zoom: 10 };
var hfValue = $("#ucDirectory_UcResults_hfResults");
$scope.directoryMarkers = [];
var createMarker = function (organization, address, latitude, longitude, i) {
var ret = {
latitude: latitude,
longitude: longitude,
address: address,
organization: organization,
show: false
};
ret.onClick = function () {
console.log("Clicked!");
ret.show = !ret.show;
};
ret["id"] = i;
return ret;
};
var json = jQuery.parseJSON(hfValue[0].value);
var markers = [];
var i = 0;
var org;
for (var key in json) {
if (json.hasOwnProperty(key)) {
org = json[key].organization;
if (json[key].address.length > 0) {
Geocoder.geocodeAddress(json[key].address).then(function (data) {
markers.push(createMarker(org, json[key].address, data.lat, data.lng, i))
$scope.map.center.latitude = data.lat;
$scope.map.center.longitude = data.lng;
});
i++;
}
}
}
$scope.directoryMarkers = markers;
});
The code in geocoder-service.js
* An AngularJS Service for intelligently geocoding addresses using Google's API. Makes use of
* localStorage (via the ngStorage package) to avoid unnecessary trips to the server. Queries
* Google's API synchronously to avoid `google.maps.GeocoderStatus.OVER_QUERY_LIMIT`.
*
* #author: benmj
* #author: amir.valiani
*
* Original source: https://gist.github.com/benmj/6380466
*/
/*global angular: true, google: true, _ : true */
'use strict';
//angular.module('geocoder', ['ngStorage']).factory('Geocoder', function ($localStorage, $q, $timeout, $rootScope) {
app.factory('Geocoder', function ($localStorage, $q, $timeout, $rootScope) {
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 QUERY_PAUSE = 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 parsedResult = {
lat: result[0].geometry.location.lat(),
lng: result[0].geometry.location.lng(),
formattedAddress: result[0].formatted_address
};
locations[task.address] = parsedResult;
$localStorage.locations = JSON.stringify(locations);
queue.shift();
task.d.resolve(parsedResult);
} 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) {
if (task.executedAfterPause) {
queue.shift();
task.d.reject({
type: 'busy',
message: 'Geocoding server is busy can not process address ' + task.address
});
}
} else if (status === google.maps.GeocoderStatus.REQUEST_DENIED) {
queue.shift();
task.d.reject({
type: 'denied',
message: 'Request denied for geocoding address ' + task.address
});
} else {
queue.shift();
task.d.reject({
type: 'invalid',
message: 'Invalid request for geocoding: status=' + status + ', address=' + task.address
});
}
if (queue.length) {
if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
var nextTask = queue[0];
nextTask.executedAfterPause = true;
$timeout(executeNext, QUERY_PAUSE);
} else {
$timeout(executeNext, 0);
}
}
if (!$rootScope.$$phase) { $rootScope.$apply(); }
});
};
return {
geocodeAddress: function (address) {
var d = $q.defer();
if (_.has(locations, address)) {
d.resolve(locations[address]);
} else {
queue.push({
address: address,
d: d
});
if (queue.length === 1) {
executeNext();
}
}
return d.promise;
}
};
});
As an aside, if you don't have a lot of windows open at the same time, you shouldn't use the windows directive, instead use the window directive and define it as a sibling to your markers. As recommended by the documentation.
But to answer the original question, this plnkr uses your code, minus the geocoding, to produce markers with windows. It takes two clicks on a marker to get to where you want it to be because the click happens before the value is changed.
I think to get the behavior you want it would look more like the following:
html:
<ui-gmap-google-map center='map.center' zoom='map.zoom' options="options">
<ui-gmap-markers fit="true" models="directoryMarkers" coords="'self'" icon="'icon'" click="'onClick'">
</ui-gmap-markers>
<ui-gmap-window show="selected.show" coords="selected">
<div>{{selected.organization}}</div>
</ui-gmap-window>
controller:
$scope.map = {
center: {
latitude: 45,
longitude: -73
},
zoom: 10
};
$scope.directoryMarkers = [];
$scope.selected = null;
var createMarker = function(latitude, longitude, i) {
var ret = {
latitude: latitude,
longitude: longitude,
organization: "Foo",
show: false
};
ret.onClick = function() {
console.log("Clicked!");
$scope.selected = ret;
ret.show = !ret.show;
};
ret["id"] = i;
return ret;
};
var markers = [];
var org;
var coords = chance.coordinates().split(",");
$scope.map.center.latitude = coords[0];
$scope.map.center.longitude = coords[1];
for (var i = 0; i < 20; i++) {
coords = chance.coordinates().split(",");
markers.push(createMarker(coords[0], coords[1], i));
}
$scope.directoryMarkers = markers;
Which can be seen tied together in this plnkr: http://plnkr.co/edit/rT4EufIGcjplgd8orVWu?p=preview

Categories