Les données Angular.js passent du service asynchique à la portée

J'ai un service comme

app.factory('geolocation', function ($rootScope, cordovaReady) { return { getCurrentPosition: cordovaReady(function (onSuccess, onError, options) { navigator.geolocation.getCurrentPosition(function () { var that = this, args = arguments; if (onSuccess) { $rootScope.$apply(function () { onSuccess.apply(that, args); }); } }, function () { var that = this, args = arguments; if (onError) { $rootScope.$apply(function () { onError.apply(that, args); }); } }, options); }), getCurrentCity: function (onSuccess, onError) { this.getCurrentPosition(function (position) { var geocoder = new google.maps.Geocoder(); geocoder.geocode(options,function (results, status) { var city = address_component.long_name; }); }); } } }); 

Et je veux faire à partir d'un contrôleur quelque chose comme

 function MainCtrl($scope, geolocation) { geolocation.getCurrentCity(function(city){ $scope.city = city; }); }; 

Le getCurrentPosition fonctionne bien et la ville est déterminée aussi, mais je ne sais pas comment accéder à la ville dans le contrôleur.

Ce qui se produit? Lorsque getCurrentCity est appelé, il appelle getCurrentPosition pour déterminer les coordonnées gps. Ces codages sont transmis comme arguments à la méthode onSuccess, n'est-ce pas? Donc, c'est tout à fait la même chose que je veux faire dans la méthode getCurrentCity, mais je ne sais pas comment. Par exemple, le géocodeur asynchien a récupéré la ville, je souhaite appliquer les nouvelles données à la méthode onSuccess.

Des idées?

Vous rencontrez des rappels et une demande asynchrone. Donc, vous devriez utiliser un service $ q . Il suffit de l'injecter dans votre service avec $ rootScope et cordovaReady de dépendance. Et ajoutez les promesses à votre fonction comme celle-ci

 getCurrentCity: function () { var deferred = $q.defer(); this.getCurrentPosition(function (position) { var geocoder = new google.maps.Geocoder(); geocoder.geocode(options,function (results, status) { var city = address_component.long_name; $rootScope.$apply(function(){ deferred.resolve(city); }); }); }); return deferred.promise; } 

Et dans votre contrôleur, procédez comme suit pour gérer la promesse.

 function MainCtrl($scope, geolocation) { geolocation.getCurrentCity().then(function(result) { //result === city $scope.city = result; //do whatever you want. This will be executed once city value is available }); }; 

Essaye ça

 function MainCtrl($scope, geolocation) { $scope.city = null; geolocation.getCurrentCity(function(city){ $scope.city = city; if(!$scope.$$phase) { $scope.$digest($scope); } }); }; 

Parfois, l'observateur n'est pas toujours appelé lors de l'instanciation du contrôleur, en forçant un événement de synthèse, si la portée n'est pas en phase, vous pouvez aller à l'endroit où vous voulez aller, je crois. Faites-moi savoir si je n'ai pas compris votre question.

Oh et je ne sais pas si j'ai bien lu le code, mais il semble que vous n'appeliez pas le rappel CallSuccess dans votre fonction: remplacez votre fonction getCurrentCity par ceci:

 getCurrentCity: function (onSuccess, onError) { this.getCurrentPosition(function (position) { var geocoder = new google.maps.Geocoder(); geocoder.geocode(options,function (results, status) { var city = address_component.long_name; if(typeof onSuccess === 'function') { onSuccess(city); } }); }); } 

Appelez simplement votre méthode onSuccess dans le service au lieu de gérer le résultat là-bas.

 getCurrentCity: function (onSuccess, onError) { this.getCurrentPosition(function (position) { var geocoder = new google.maps.Geocoder(); geocoder.geocode(options, onSuccess); }); } 

Et dans votre contrôleur, analysez les résultats et attribuez la ville:

 function MainCtrl($scope, geolocation) { geolocation.getCurrentCity(function(results, status){ // Parse results for the city - not sure what that object looks like $scope.city = results.city; }); }; 

Corrigez-moi si je me trompe, mais la solution présentée ne fonctionnera plus complètement, car les nouvelles versions angulaires (> 1.2 !?) ne déploient plus de promesses $ q automatiquement.

Ainsi:

 $scope.city = geolocation.getCurrentCity(); 

Sera toujours une promesse. Donc, vous devrez toujours utiliser:

 geolocation.getCurrentCity().then(function(city) { $scope.city = city; }