Как $HTTP Синхронный вызов с помощью AngularJS

Извините за мой вопрос о новичке, но документация AngularJS не очень ясна или обширна для выяснения некоторых основных вещей.

Есть ли способ сделать синхронный вызов с помощью AngularJS?

В сервисе:

myService.getByID = function (id) {
    var retval = null;

    $http({
        url: "/CO/api/products/" + id,
        method: "GET"
    }).success(function (data, status, headers, config) {

        retval = data.Data;

    });

    return retval;
}

Ответ 1

В настоящее время нет. Если вы посмотрите исходный код (с этого момента времени Oct 2012), вы увидите, что вызов XHR open на самом деле является жестким, закодирован как асинхронный (третий параметр имеет значение true):

 xhr.open(method, url, true);

Вам нужно будет написать свой собственный сервис, который выполнял бы синхронные вызовы. Как правило, это не то, что вы обычно хотите делать из-за характера выполнения JavaScript, вы в конечном итоге блокируете все остальное.

... но.. если блокировка всего остального на самом деле желательна, возможно, вам стоит заглянуть в promises и $q service. Это позволяет подождать до тех пор, пока не будет выполнен набор асинхронных действий, а затем выполните что-то, как только они будут завершены. Я не знаю, каков ваш вариант использования, но это может стоить взгляда.

Кроме того, если вы собираетесь сворачивать самостоятельно, больше информации о том, как делать синхронные и асинхронные вызовы ajax можно найти здесь.

Я надеюсь, что это будет полезно.

Ответ 2

Я работал с factory, интегрированным с автозаполнением карт google и promises, я надеюсь, что вы будете обслуживать.

http://jsfiddle.net/the_pianist2/vL9nkfe3/1/

вам нужно только заменить autocompleteService на этот запрос с $http incuida, который находится перед factory.

app.factory('Autocomplete', function($q, $http) {

и $http с

 var deferred = $q.defer();
 $http.get('urlExample').
success(function(data, status, headers, config) {
     deferred.resolve(data);
}).
error(function(data, status, headers, config) {
     deferred.reject(status);
});
 return deferred.promise;

<div ng-app="myApp">
  <div ng-controller="myController">
  <input type="text" ng-model="search"></input>
  <div class="bs-example">
     <table class="table" >
        <thead>
           <tr>
              <th>#</th>
              <th>Description</th>
           </tr>
        </thead>
        <tbody>
           <tr ng-repeat="direction in directions">
              <td>{{$index}}</td>
              <td>{{direction.description}}</td>
           </tr>
        </tbody>
     </table>
  </div>

'use strict';
 var app = angular.module('myApp', []);

  app.factory('Autocomplete', function($q) {
    var get = function(search) {
    var deferred = $q.defer();
    var autocompleteService = new google.maps.places.AutocompleteService();
    autocompleteService.getPlacePredictions({
        input: search,
        types: ['geocode'],
        componentRestrictions: {
            country: 'ES'
        }
    }, function(predictions, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            deferred.resolve(predictions);
        } else {
            deferred.reject(status);
        }
    });
    return deferred.promise;
};

return {
    get: get
};
});

app.controller('myController', function($scope, Autocomplete) {
$scope.$watch('search', function(newValue, oldValue) {
    var promesa = Autocomplete.get(newValue);
    promesa.then(function(value) {
        $scope.directions = value;
    }, function(reason) {
        $scope.error = reason;
    });
 });

});

сам вопрос должен быть сделан:

deferred.resolve(varResult); 

когда вы сделали хорошо, и запрос:

deferred.reject(error); 

когда есть ошибка, а затем:

return deferred.promise;

Ответ 3

Недавно я столкнулся с ситуацией, когда мне захотелось сделать $http-вызовы, вызванные перезагрузкой страницы. Решение, с которым я пошел:

  • Инкапсулировать два вызова в функции
  • Передайте второй вызов $http в качестве обратного вызова во вторую функцию
  • Вызов второй функции в apon.success

Ответ 4

var EmployeeController = ["$scope", "EmployeeService",
        function ($scope, EmployeeService) {
            $scope.Employee = {};
            $scope.Save = function (Employee) {                
                if ($scope.EmployeeForm.$valid) {
                    EmployeeService
                        .Save(Employee)
                        .then(function (response) {
                            if (response.HasError) {
                                $scope.HasError = response.HasError;
                                $scope.ErrorMessage = response.ResponseMessage;
                            } else {

                            }
                        })
                        .catch(function (response) {

                        });
                }
            }
        }]


var EmployeeService = ["$http", "$q",
            function ($http, $q) {
                var self = this;

                self.Save = function (employee) {
                    var deferred = $q.defer();                
                    $http
                        .post("/api/EmployeeApi/Create", angular.toJson(employee))
                        .success(function (response, status, headers, config) {
                            deferred.resolve(response, status, headers, config);
                        })
                        .error(function (response, status, headers, config) {
                            deferred.reject(response, status, headers, config);
                        });

                    return deferred.promise;
                };

Ответ 5

Здесь вы можете сделать это асинхронно и управлять такими вещами, как обычно. Все по-прежнему разделяется. Вы получаете ссылку на объект, который хотите обновить. Всякий раз, когда вы обновляете это в своей службе, он обновляется во всем мире без необходимости смотреть или возвращать обещание. Это действительно приятно, потому что вы можете обновить базовый объект из службы, не перегружая его. Используя Angular способ использования. Я думаю, что это, вероятно, плохая идея сделать $http.get/post synchronous. Вы получите заметную задержку в script.

app.factory('AssessmentSettingsService', ['$http', function($http) {
    //assessment is what I want to keep updating
    var settings = { assessment: null };

    return {
        getSettings: function () {
             //return settings so I can keep updating assessment and the
             //reference to settings will stay in tact
             return settings;
        },
        updateAssessment: function () {
            $http.get('/assessment/api/get/' + scan.assessmentId).success(function(response) {
                //I don't have to return a thing.  I just set the object.
                settings.assessment = response;
            });
        }
    };
}]);

    ...
        controller: ['$scope', '$http', 'AssessmentSettingsService', function ($scope, as) {
            $scope.settings = as.getSettings();
            //Look.  I can even update after I've already grabbed the object
            as.updateAssessment();

И где-то в представлении:

<h1>{{settings.assessment.title}}</h1>

Ответ 6

Как обернуть ваш вызов в методе Promise.all() i.e.

Promise.all([$http.get(url).then(function(result){....}, function(error){....}])

Согласно MDN

Promise.all ждет всех исполнений (или первого отказа)