角。js将数据从异步服务传递到范围

时间:2022-02-25 12:58:30

I have a service like

我有类似的服务

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

And I want to do from a controller something like

我想从控制器中做一些类似的事情

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

The getCurrentPosition works fine and the city is determined too, however I don't know how to access the city in controller.

getCurrentPosition工作正常,城市也确定,但是我不知道如何在controller中访问城市。

What happens? When getCurrentCity is called, it calles getCurrentPosition to determine the gps coords. This coords are passed as arguments to the onSuccess method right? So this is quite the same I want to do in the getCurrentCity method, but I don't know how. Ones the async geocoder retrieved the city, I want to apply the new data to the onSuccess method.

会发生什么呢?调用getCurrentCity时,它调用getCurrentPosition来确定gps coord。这个coord作为onSuccess方法的参数传递,对吧?这和我想在getCurrentCity方法中做的是一样的,但是我不知道怎么做。异步geocoder检索了城市之后,我想将新的数据应用到onSuccess方法。

Any ideas?

什么好主意吗?

4 个解决方案

#1


29  

You are dealing with callbacks and asynchronous request. So you should use $q service. Just inject it in your service with $rootScope and cordovaReady dependency. And add the promises to your function like this

您正在处理回调和异步请求。所以你应该使用$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;
}

And in your controller, do the following to handle the 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
   });     
};

#2


5  

Try this

试试这个

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

Sometimes, the watcher is not always called when instanciating the controller, by forcing a digest event, if the scope is not in phase, you can go to where you want to go, I believe. Let me know if I didn't understand your question.

有时,在实例化控制器时并不总是调用监视程序,通过强制执行摘要事件,如果范围不在阶段中,我相信您可以到达您想去的地方。如果我不明白你的问题,请告诉我。

Oh and I don't know if i read the code properrly but it seems that you're not calling the onSuccess callback in your function: replace your getCurrentCity function by this:

哦,我不知道我是否正确读取了代码,但似乎你并没有调用函数中的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);
                }
            });
        });
    }

#3


4  

Just call your onSuccess method in the service instead of handling the result there.

只需在服务中调用onSuccess方法,而不是在那里处理结果。

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

And in your controller, parse the results and assign the city:

在控制器中,解析结果并分配城市:

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

#4


3  

Correct me if I'm wrong, but the presented solution won't work completely anymore, since newer Angular versions (>1.2!?) do no longer unwrap $q promises automatically.

如果我错了,请纠正我,但是目前的解决方案将不再完全有效,因为更新的角度版本(>1.2!?)不再自动打开$q承诺。

Thus:

因此:

$scope.city = geolocation.getCurrentCity();

will always be a promise. So you will always have to use:

将永远是一个承诺。所以你必须一直使用:

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

#1


29  

You are dealing with callbacks and asynchronous request. So you should use $q service. Just inject it in your service with $rootScope and cordovaReady dependency. And add the promises to your function like this

您正在处理回调和异步请求。所以你应该使用$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;
}

And in your controller, do the following to handle the 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
   });     
};

#2


5  

Try this

试试这个

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

Sometimes, the watcher is not always called when instanciating the controller, by forcing a digest event, if the scope is not in phase, you can go to where you want to go, I believe. Let me know if I didn't understand your question.

有时,在实例化控制器时并不总是调用监视程序,通过强制执行摘要事件,如果范围不在阶段中,我相信您可以到达您想去的地方。如果我不明白你的问题,请告诉我。

Oh and I don't know if i read the code properrly but it seems that you're not calling the onSuccess callback in your function: replace your getCurrentCity function by this:

哦,我不知道我是否正确读取了代码,但似乎你并没有调用函数中的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);
                }
            });
        });
    }

#3


4  

Just call your onSuccess method in the service instead of handling the result there.

只需在服务中调用onSuccess方法,而不是在那里处理结果。

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

And in your controller, parse the results and assign the city:

在控制器中,解析结果并分配城市:

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

#4


3  

Correct me if I'm wrong, but the presented solution won't work completely anymore, since newer Angular versions (>1.2!?) do no longer unwrap $q promises automatically.

如果我错了,请纠正我,但是目前的解决方案将不再完全有效,因为更新的角度版本(>1.2!?)不再自动打开$q承诺。

Thus:

因此:

$scope.city = geolocation.getCurrentCity();

will always be a promise. So you will always have to use:

将永远是一个承诺。所以你必须一直使用:

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