Как $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-вызовы, вызванные перезагрузкой страницы. Решение, которое я выбрал:
- Инкапсулировать два вызова в функции
- Передайте второй вызов $http в качестве обратного вызова во вторую функцию
- Вызовите вторую функцию в 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 ждет всех исполнений (или первого отклонения)