Возврат последнего значения связанных обещаний в angular

Я пытаюсь сделать некоторую геолокацию и на основе координат вызвать RESTful API, который возвращает некоторые данные. Затем я хочу проанализировать эти данные и, наконец, вернуть их. Я новичок в angular.js и обещаниях, поэтому этот код представляет собой смесь вещей, которые я видел в Интернете: D

Я заставил все это работать, но упустил последний шаг: возврат обработанного массива результатов ("allSpots") исходному вызывающему абоненту. Что мне здесь не хватает?

.factory('wifiSpotFactory', function (WifinderModel, $q, $http) {

            function onGeolocationSuccess(position) {

            var url = 'http://localhost:34915/api/spots?latitude=' + position.coords.longitude + '&longitude=' + position.coords.latitude;

            $http.get(url).then(function (response) {

                var allSpots = [], data = response.data;
                for (var i = 0; i < data.length; i++) {
                    var newSpot = new WifinderModel.wifiSpot(data[i].id, data[i].name, data[i].password, data[i].address);
                    allSpots.push(newSpot);
                }

                return allSpots;

            }, function (error) {
                console.log(error);
            });

        };

            var wifiSpotFactory = {
                loadNearSpots: function() {
                var geo_options = {
                    enableHighAccuracy: true,
                    maximumAge: 50000,
                    timeout: 30000
                };

                var deferred = $q.defer();

                navigator.geolocation.getCurrentPosition(deferred.resolve, deferred.reject, geo_options);

                return deferred.promise
                        .then(onGeolocationSuccess)
                        .then(function(allSpots) { return allSpots; });
            }
            };
            return wifiSpotFactory;
            } )

Затем в контроллере, как мне получить значение обещания?

.controller('wifiListController', [
                '$scope', 'wifiSpotFactory', function ($scope, wifiSpotFactory) {
                    $scope.spots = wifiSpotFactory.loadNearSpots();
               }
])

person Daniel Perez    schedule 28.10.2015    source источник
comment
Так что же возвращает WifinderModel.wifiSpot() — ценность или обещание?   -  person Roamer-1888    schedule 29.10.2015
comment
который возвращает значение -- экземпляр класса   -  person Daniel Perez    schedule 29.10.2015
comment
Ммм, в таком случае решение Pankaj Parkar выглядит так, как будто оно должно работать.   -  person Roamer-1888    schedule 30.10.2015


Ответы (2)


Callback не имеет возможности возвращать данные, вы действительно должны использовать там шаблон обещания, который имел бы возможность возвращать данные из обещания. Вы onGeolocationSuccess используете шаблон обратного вызова, который кажется return data, но на самом деле это не так.

Вы можете решить проблему, просто вернув обещание из метода onGeolocationSuccess, для этого вам нужно вернуть объект $http.get, который уже возвращает объект обещания. В .then этой функции вы получите data, который вернулся из API. Из функции .then вы можете вернуть data, который поможет вам следовать образец обещания.

Код

.factory('wifiSpotFactory', function(WifinderModel, $q, $http) {

  function onGeolocationSuccess(position) {
    var url = 'http://localhost:34915/api/spots?latitude=' + position.coords.longitude + '&longitude=' + position.coords.latitude;

    return $http.get(url).
    then(function(response) {
      var allSpots = [],
          data = response.data;
      for (var i = 0; i < data.length; i++) {
        var newSpot = new WifinderModel.wifiSpot(data[i].id, data[i].name, data[i].password, data[i].address);
        allSpots.push(newSpot);
      }
      return allSpots;

    }, function(error) {
      console.log(error)
    });
  };

  var wifiSpotFactory = {
    loadNearSpots: function() {
      //..other code as is..to make solution cleaner removed that part.
      //return promise to follow promise chain
      return deferred.promise
      .then(onGeolocationSuccess)
      .then(function(allSpots) {
        return allSpots;
      });
    }
  };
  return wifiSpotFactory;
})

Контроллер

.controller('wifiListController', ['$scope', 'wifiSpotFactory', 
   function ($scope, wifiSpotFactory) {
       wifiSpotFactory.loadNearSpots().then(function(data){
           $scope.spots = data; //data will be available inside `.then` which promise resolve/reject
       });
   }
])
person Pankaj Parkar    schedule 28.10.2015
comment
не могли бы вы немного помочь мне с полным кодом? я понял изменение onGeolocationSuccess, но я не уверен, как должно быть все остальное - person Daniel Perez; 28.10.2015
comment
не работает должным образом: loadNearSpots: function() { var deferred = $q.defer(); navigator.geolocation.getCurrentPosition(deferred.resolve, deferred.reject); deferred.promise .then(onGeolocationSuccess) .then(function(allSpots) { return allSpots; }); } - person Daniel Perez; 28.10.2015
comment
@DanielPerez должно возвращать обещание типа return deferred.promise.then(function (position) { return onGeolocationSuccess(position); - person Pankaj Parkar; 28.10.2015
comment
я все еще не понимаю :( если бы вы могли привести пример для функции loadNearSpots, как и для остальных, это мне очень помогло бы - person Daniel Perez; 28.10.2015
comment
я обновил код, чтобы отразить предлагаемые изменения - person Daniel Perez; 28.10.2015
comment
@DanielPerez посмотри мое обновление в коде... вернул обещание, которое ты пропустил... посмотри на комментарий - person Pankaj Parkar; 28.10.2015
comment
спасибо, я добавил это. Теперь последний шаг (см. код), в контроллере мне нужно сделать что-то особенное? Я имею в виду, когда я дохожу до конца и хочу получить фактическое значение (остановить цепочку), как я могу это сделать? - person Daniel Perez; 28.10.2015
comment
@DanielPerez посмотрите на мою правку... ничего особенного. ожидайте данные в функции promise.then... вот и все :) - person Pankaj Parkar; 28.10.2015
comment
Я думаю, что я получаю это сейчас. Я пробовал, вроде работает, но есть небольшая проблема. Я проверил с помощью отладчика, и порядок выполнения не соответствует ожидаемому. пример: $scope.spots = data вызывается до $http, поэтому данные пусты. но позже заполняется allSpots. почему это? - person Daniel Perez; 28.10.2015
comment
@DanielPerez не может многого догадаться, не видя работающий код.. Извините, что говорю это.. - person Pankaj Parkar; 28.10.2015

Вернуть обещание для цепочки:

function onGeolocationSuccess(position) {
  var url = 'http://localhost:34915/api/spots?latitude=' + position.coords.longitude + '&longitude=' + position.coords.latitude;

  return $http.get(url).success(function(data, status, headers, config) {
    var allSpots = [];
    for (var i = 0; i < data.length; i++) {
      var newSpot = new WifinderModel.wifiSpot(data[i].id, data[i].name, data[i].password, data[i].address);
      allSpots.push(newSpot);
    }

    return allSpots;

  }).error(function(data, status, headers, config) {});
};

Тогда вызов может быть:

deferred.promise
.then(onGeolocationSuccess)
.then(function(allSpots) { ... });
person tcooc    schedule 28.10.2015
comment
я пробовал это, но не работает для меня. allSpots на последнем то пусто - person Daniel Perez; 28.10.2015
comment
я обновил код, чтобы отразить предлагаемые изменения - person Daniel Perez; 28.10.2015