11

私は次のようなサービスを持っています

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

そして、コントローラーから次のようなことをしたい

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

getCurrentPosition は正常に機能し、都市も決定されますが、コントローラーで都市にアクセスする方法がわかりません。

何が起こるのですか?getCurrentCity が呼び出されると、getCurrentPosition が呼び出されて GPS 座標が決定されます。この座標は引数として onSuccess メソッドに渡されますよね?したがって、これは getCurrentCity メソッドでやりたいこととまったく同じですが、方法がわかりません。非同期ジオコーダが都市を取得したので、新しいデータを onSuccess メソッドに適用したいと思います。

何か案は?

4

4 に答える 4

29

コールバックと非同期リクエストを扱っています。したがって、$qサービスを使用する必要があります。$rootScope と cordovaReady の依存関係を使用してサービスに挿入するだけです。そして、このように関数に約束を追加します

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

そしてコントローラーで、次のようにして promise を処理します。

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
   });     
};
于 2013-07-23T23:59:55.207 に答える
5

これを試して

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

時々、コントローラーのインスタンス化時にウォッチャーが常に呼び出されるわけではありません。ダイジェスト イベントを強制することで、スコープがフェーズにない場合は、行きたい場所に行くことができると思います。あなたの質問が理解できなかった場合はお知らせください。

ああ、コードを正しく読んだかどうかはわかりませんが、関数で onSuccess コールバックを呼び出していないようです: getCurrentCity 関数を次のように置き換えてください:

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);
                }
            });
        });
    }
于 2013-07-24T09:32:42.923 に答える
3

私が間違っている場合は訂正してください。ただし、新しい Angular バージョン (>1.2!?) では $q プロミスが自動的にアンラップされないため、提示されたソリューションは完全には機能しなくなります。

したがって:

$scope.city = geolocation.getCurrentCity();

いつでも約束です。したがって、常に使用する必要があります:

geolocation.getCurrentCity().then(function(city) {
    $scope.city = city;
}
于 2014-01-10T14:24:16.477 に答える