Часто при использовании AJAX зыдумываюсь о том, как было бы круто уведомлять пользователей о стадии запроса. Что бы всё это было автоматически, но в итоге каждый раз обходился парой костылейю...
Для начала создадим само модальное окно с дополнительными примочками:
<div class="modal fade" id="processing-modal" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false" style="z-index: 1000000000">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" style="border:0">
<h4 class="modal-title text-center">Processing...</h4>
</div>
<div class="modal-body"></div>
</div>
</div>
</div>
- data-backdrop="static" и data-keyboard="false" предотвращает закрытие окна по клику
- style="z-index: 1000000000" выводит модальное окно поверх всех существующих слоёв
Далее добавим в div.modal-body значок выполнения действия, а так же прогрессбар, который будет вылезать при > 1 запросах давая понять пользователю что система не зависла, а всё ещё в процессе.
<div class="text-center" style="padding-bottom:15px">
<i class="fa fa-spinner fa-pulse fa-5x"></i>
</div>
<div class="progress" style="margin: 10px 0; display:none">
<div class="progress-bar progress-bar-striped active" role="progressbar"></div>
</div>
Теперь самое время обратится к документации jQuery, а именно нам понадобится ajaxSetup и его методы:
- beforeSend - выстреливает перед отправкой запроса
- complete - выстреливает после получения запроса
- error - выстреивает при ошибке запроса
Алгоритм довольно прост: Создаём глобальный счётчик запросов, который увеличиваем при каждом запросе и уменьшаем при получении ответа. Так же перед каждым запросом проверяем количество выполняемых в данный момент запросов и если их больше 1 то показываем прогресбар.
var processing_modal = jQuery('#processing-modal');
function isNumber(number) {
return !isNaN(parseFloat(number)) && isFinite(number);
}
jQuery.ajaxSetup({
// Выполнение перед запросом
'beforeSend': function() {
// Создаём счётчик если он не существует
if (isNumber(window.ajax_counter) == false)
window.ajax_counter = 0;
// Показываем модальное окно если оно спрятано
if (window.ajax_counter == 0)
processing_modal.modal('show');
// Увеличиваем счётчик
window.ajax_counter++;
// Если запросов больше одного то показывае прогрессбар
if (window.ajax_counter > 1) {
var pb = processing_modal.find('.progress').show();
// Обнуляем прогрессбар в начале запросов
if (window.ajax_counter == 2)
pb.find('.progress-bar').css('width', '0');
}
},
// Выполнение после запроса
'complete': function(response) {
// Создаём счётчик максимального количества запросов
// Он нужен для того, что бы знать количество запросов для подсчёта прогресса
if (isNumber(window.ajax_max) == false)
window.ajax_max = 0;
// Увеличиваем если появляется новый запрос
if (window.ajax_counter > window.ajax_max)
window.ajax_max = window.ajax_counter;
// Уменьшаем количество запросов
window.ajax_counter--;
// Высчитываем прогресс
var progress = 100 - (100 / window.ajax_max) * window.ajax_counter;
// Устанавливаем прогресс
processing_modal.find('.progress').show().find('.progress-bar').css('width', progress + '%');
// Прячем окно если все запросы выполнены
if (window.ajax_counter == 0) {
processing_modal.modal('hide');
processing_modal.find('.progress').hide().find('.progress-bar').css('width', '0');
window.ajax_max = 0;
}
},
// В случае какой-либо ошибки выводим сообщение и прячем окно
'error': function(xmlHttpRequest, textStatus, errorThrown) {
alert('A critical error has occured. Please reload the page and try again.');
processing_modal.modal('hide');
},
});