На моей веб-странице, когда пользователь нажимает кнопку загрузки, из контроллера вызывается действие экспорта, создается файл Excel, а затем возвращается пользователю. В зависимости от параметров, переданных действию, иногда создание файла и его возврат пользователю может занять некоторое время.
Итак, я хочу показать индикатор занятости во время ожидания файла. Я пошел с Bootstrap spinner.
$('.content').on('click', 'a.export', function (e) {
e.preventDefault();
// show busy indicator
$('#divSpinner').css('display', 'inline-block');
var idSelect = '';
$('#ddlSelect option:selected').each(function () {
idSelect += $('#ddlSelect')[0].value;
});
var idSelect2 = '';
$('#ddlSelect2 option:selected').each(function () {
idSelect2 += $('#ddlSelect2')[0].value;
});
var url = 'Home/Exports?' + 'param1=' + idSelect + '¶m2=' + idSelect2;
//download file
window.location = url;
// hide busy indicator
$('#divSpinner').css('display', 'none');
});
Ну, этот вид работ, но проблема в том, что $ ('# divSpinner'). css ('display', 'none' ); получает немедленный удар, и счетчик прячется до того, как файл фактически станет доступен пользователю для загрузки (загрузка / открытие в браузере).
Как мне переписать код для ожидания окна .location = url в fini sh, а затем скрыть счетчик?
РЕДАКТИРОВАТЬ: Я также пытался обернуть часть Download в асинхронную c функцию следующим образом:
async function Download(url) {
let promise = new Promise((resolve, reject) => {
resolve(window.location = url);
});
let result = await promise; // wait until the promise resolves (*)
}
и называет это так:
Download(url)
.then(function() {
$('#divSpinner').hide()
});
Загрузка работает, но все же $('#divSpinner').hide()
get получает, прежде чем загрузка файла будет представлена пользователю. Разве весь смысл асинхронного / ожидающего ожидания результата перед продолжением выполнения кода ??
EDIT2 (с «blob»):
async function Download(url) {
let promise = new Promise((resolve, reject) => {
resolve(filedownload(url));
});
let result = await promise;
}
function filedownload(urlToSend) {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var fileName = req.getResponseHeader("fileName")
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
};
req.send();
}
и вызывая его так:
Download(url)
.then(function() {
$('#divSpinner').hide()
});
EDIT 3 : я использовал решение @ Nenad снизу, но я изменил только обработку заголовка ответа (в противном случае я получал NULL для имени файла при загрузке - я использовал это решение { ссылка }):
function filedownload(urlToSend, resolve) {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var filename = "";
var disposition = req.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
resolve(filename); // call resolve after download has finished.
};
req.send();
}