AngularJS: повтор последних запросов при обрыве соединения

Решил сделать кнопку «обновить», которая показывается при обрыве сетевого соединения и повторяет неудавшиеся запросы. Очень актуально для мобильных приложений.

Задача состоит из двух частей:

  1. Запросы к api на уже сформированной странице (сохранение форм и другие действия без смены контроллера и урла)
  2. Переход на новый урл (смена через маршрутизацию AngularJS)

Первое у меня сделано через расширение $resource (сделано оно изначально было для другого, но и этот функционал туда вписывается хорошо).
Вкратце идея такова: каждый запрос заносится в объект-хранилище; когда запрос успешно выполняется, он из этого хранилища выбрасывается. Если запрос не был выполнен, то его параметры остаются в хранилище, а в $rootScope ставится флаг, говорящий о том, что произошёл сбой при соединении с api. При этом показывается кнопка «повторить последние запросы», при нажатии на которую сохранённые запросы выполняются заново.

А хотел я остановиться на втором пункте, т.к. реализация не требует расширения библиотеки angular, а реализуется штатными средствами, да к тому же и кода немного.
При смене урла AngularJS сначала делает запрос для загрузки шаблона, и если он не отработал, то выполнение логики контроллера не начинается (кстати, именно поэтому в шаблоне обязательно нужен контент, без него контроллер работать не будет).
Если шаблон не загрузился, то будет сгенерировано событие $routeChangeError. Вешаем обработчик на это событие, который ставит переменную в $rootScope. Для повтора загрузки шаблона и дальнейшего выполнения логики контроллера достаточно выполнить $route.reload();. Так что вот весь код:

app.js

(function ()
{
	$rootScope.routeError = false;
	$rootScope.$on('$routeChangeError', function (event, current, prev, rejection) {
		$rootScope.routeError = true;
	});

	$rootScope.$on('requests.rerun', function (event, current, prev, rejection) {
		if ($rootScope.routeError)
		{
			$route.reload();
			$rootScope.routeError = false;
		}
	});

}());

$rootScope.rerunRequests = function rerunRequests()
{
	$rootScope.$emit('requests.rerun');
};

index.html

<div ng-show="controllerDataLoadError || routeError">
	<a href="javascript:;" ng-click="rerunRequests()">Повторить последний запрос</a>
</div>

Единственный минус такого подхода

Если вместо callback-ов используются прямое присваивание значения, то повтор запроса не вернет это значение в нужное место. Выход — не использовать такой синтаксис, тем более, что он менее удобен.
Т.е. не надо вместо

MyService.get(params, function (response) {
	$scope.response = response;
	$scope.$emit('extendedGeoSelector.show');

	LoadRendererService.setLoaded();
});

использовать

$scope.response = MyService.get(params);

LEAVE A COMMENT