Как $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;
}

7 ответов

Решение

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

 xhr.open(method, url, true);

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

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

Помимо этого, если вы собираетесь развернуть свой собственный, здесь можно найти дополнительную информацию о том, как выполнять синхронные и асинхронные вызовы AJAX.

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

Я работал с заводом, интегрированным с автозаполнением карт Google и дал обещания, надеюсь, вы выполняете.

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

Вам нужно всего лишь заменить autocompleteService этим запросом на $ http incuida до фабрики.

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

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

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

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

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>

Поскольку синхронизация XHR устарела, лучше не полагаться на это. Если вам нужно выполнить запрос POST синхронизации, вы можете использовать следующие помощники внутри службы для имитации публикации формы.

Он работает путем создания формы со скрытыми входными данными, которая публикуется по указанному URL-адресу.

//Helper to create a hidden input
function createInput(name, value) {
  return angular
    .element('<input/>')
    .attr('type', 'hidden')
    .attr('name', name)
    .val(value);
}

//Post data
function post(url, data, params) {

    //Ensure data and params are an object
    data = data || {};
    params = params || {};

    //Serialize params
    const serialized = $httpParamSerializer(params);
    const query = serialized ? `?${serialized}` : '';

    //Create form
    const $form = angular
        .element('<form/>')
        .attr('action', `${url}${query}`)
        .attr('enctype', 'application/x-www-form-urlencoded')
        .attr('method', 'post');

    //Create hidden input data
    for (const key in data) {
        if (data.hasOwnProperty(key)) {
            const value = data[key];
            if (Array.isArray(value)) {
                for (const val of value) {
                    const $input = createInput(`${key}[]`, val);
                    $form.append($input);
                }
            }
            else {
                const $input = createInput(key, value);
                $form.append($input);
            }
        }
    }

    //Append form to body and submit
    angular.element(document).find('body').append($form);
    $form[0].submit();
    $form.remove();
}

Изменить в соответствии с вашими потребностями.

Как насчет упаковки вашего звонка в Promise.all() метод т.е.

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

По данным МДН

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

Другие вопросы по тегам