web-dev-qa-db-fra.com

Comment effectuer un appel $ http synchrone avec AngularJS

Désolé pour ma question d'internaute débutante, mais la documentation d'AngularJS n'est pas très explicite ou exhaustive pour comprendre quelques éléments de base.

Est-il possible de faire un appel synchrone avec AngularJS?

SUR UN SERVICE:

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;
}
130
Flavio Oliveira

Pas actuellement. Si vous regardez le code source (à partir de ce moment-là Oct 2012) , vous verrez que l'appel à XHR open est en réalité codé en dur pour être asynchrone (le troisième paramètre est vrai):

 xhr.open(method, url, true);

Vous devez écrire votre propre service qui effectue des appels synchrones. Généralement, ce n’est pas quelque chose que vous voudrez faire, étant donné la nature de l’exécution de JavaScript, vous finirez par bloquer tout le reste.

... mais ... si vous souhaitez bloquer tout le reste, vous devriez peut-être vous pencher sur les promesses et le $ q service . Il vous permet d'attendre qu'un ensemble d'actions asynchrones soit terminé, puis d'exécuter quelque chose une fois qu'elles sont toutes terminées. Je ne sais pas quel est votre cas d'utilisation, mais cela pourrait valoir le coup d'oeil.

En dehors de cela, si vous voulez lancer votre propre, plus d'informations sur la façon de faire des appels ajax synchrones et asynchrones peut être trouvé ici .

J'espère que c'est utile.

112
Ben Lesh

J'ai travaillé avec une usine intégrée avec Google Maps, la saisie semi-automatique et les promesses faites, j'espère que vous servirez.

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

il vous suffit de remplacer autocompleteService par cette requête par $ http incuida avant l’usine.

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

et demande $ http avec

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

});

la question elle-même est à poser sur:

deferred.resolve(varResult); 

quand vous avez bien fait et la demande:

deferred.reject(error); 

quand il y a une erreur, puis:

return deferred.promise;
12
allel
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
Srinivas

Je me suis récemment retrouvé dans une situation où je voulais effectuer des appels $ http déclenchés par un rechargement de page. La solution je suis allé avec:

  1. Encapsuler les deux appels en fonctions
  2. Passer le deuxième appel $ http comme rappel dans la deuxième fonction
  3. Appelez la deuxième fonction après .success
4
vikas agartha

Voici un moyen de le faire de manière asynchrone et de gérer les choses comme vous le feriez normalement. Tout est encore partagé. Vous obtenez une référence à l'objet que vous souhaitez mettre à jour. Chaque fois que vous mettez à jour cela dans votre service, il est mis à jour globalement sans avoir à regarder ou à retourner une promesse. C’est vraiment agréable, car vous pouvez mettre à jour l’objet sous-jacent depuis le service sans avoir à vous relier. Utiliser Angular comme il est censé être utilisé. Je pense que c'est probablement une mauvaise idée de rendre $ http.get/post synchrone. Vous aurez un retard notable dans le 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();

Et quelque part dans une vue:

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

Puisque sync XHR est obsolète, il est préférable de ne pas compter sur cela. Si vous devez effectuer une demande de synchronisation POST, vous pouvez utiliser les assistants suivants à l'intérieur d'un service pour simuler une publication de formulaire.

Cela fonctionne en créant un formulaire avec des entrées cachées qui sont postées à l'URL spécifiée.

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

Modifiez selon vos besoins.

0
Adam Reis