2013-07-16 11 views
11

Ich habe einen Dienst wieAngularjs passieren Daten von Asynchron-Service zum Umfang

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; 
       }); 
      }); 
     } 
    } 
}); 

Und ich will von einem Controller, etwas zu tun wie

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

Die getCurrentPosition funktioniert gut und die Stadt ist bestimmt auch, aber ich weiß nicht, wie man in der Steuerung auf die Stadt zugreift.

Was passiert? Wenn getCurrentCity aufgerufen wird, ruft es getCurrentPosition auf, um die GPS-Koordinaten zu ermitteln. Diese Coords werden als Argumente an die onSuccess-Methode übergeben, oder? Das ist genau das gleiche, was ich in der Methode getCurrentCity machen möchte, aber ich weiß nicht wie. Sobald der asynchrone Geocoder die Stadt abgerufen hat, möchte ich die neuen Daten auf die onSuccess-Methode anwenden.

Irgendwelche Ideen?

Antwort

29

Sie mit Rückrufen und asynchroner Anforderung handeln. Sie sollten also den Dienst $q verwenden. Injizieren Sie es einfach mit $ rootScope und cordovaReady in Ihren Dienst. und fügen Sie das Versprechen an Ihre Funktion wie diese

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; 
} 

Und in Ihrem Controller Sie wie folgt vor, das Versprechen zu behandeln.

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 
    });  
}; 
+0

Mein Problem behoben, ich hatte einen Filter, der die Schleife verursachte. –

+0

Der erste Ansatz in der obigen Controller-Implementierung, eine $ scope-Eigenschaft auf ein Versprechen zu setzen, funktioniert in Angular 1.3 nicht mehr.Versprechen werden nicht mehr ausgepackt, daher müssen Sie den zweiten Ansatz verwenden (indem Sie die $ scope-Eigenschaft im then-Handler festlegen) – jbandi

+0

@jbandi: Sie scheinen darauf hinzuweisen, dass sich etwas geändert hat. Ich habe nicht verstanden, was genau die Änderung ist. Macht es dir etwas aus, es für mich zu erklären? Ich werde die Antwort entsprechend aktualisieren. –

4

Rufen Sie einfach Ihre onSuccess-Methode im Service auf, anstatt das Ergebnis dort zu bearbeiten.

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

Und in Ihrem Controller, um die Ergebnisse analysieren und die Stadt zuordnen:

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; 
    }); 
}; 
5

Versuchen Sie, diese

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

Manchmal wird der Beobachter nicht immer aufgerufen, wenn der Controller Instanziierung, durch ein Ereignis verdauen zu zwingen, wenn der Umfang nicht in Phase ist, können Sie gehen, wo Sie wollen zu gehen, glaube ich. Lass es mich wissen, wenn ich deine Frage nicht verstanden habe.

Oh, und ich weiß nicht, ob ich den Code properrly lesen, aber es scheint, dass Sie nicht die onSuccess Rückruf in Ihrer Funktion aufrufen: ersetzen Ihre getCurrentCity Funktion durch das:

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); 
       } 
      }); 
     }); 
    } 
3

Korrigieren Sie mich, wenn ich falsch liege, aber die vorgestellte Lösung wird nicht mehr ganz funktionieren, da neuere Angular-Versionen (> 1.2 !?) $ q Versprechen nicht mehr automatisch auspacken.

So:

$scope.city = geolocation.getCurrentCity(); 

wird immer ein Versprechen sein. Du wirst also immer folgendes brauchen:

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