Как определить, когда пользователь отменяет вход файла с помощью ввода файла html?
onChange позволяет мне определять, когда они выбирают файл, но я также хотел бы знать, когда они отменяют (закройте диалог выбора файла, не выбирая ничего).
Как определить, когда пользователь отменяет вход файла с помощью ввода файла html?
onChange позволяет мне определять, когда они выбирают файл, но я также хотел бы знать, когда они отменяют (закройте диалог выбора файла, не выбирая ничего).
Хотя это не прямое решение, а также плохое в том, что только (насколько я проверял) работает с onfocus (требуется довольно ограничивающая блокировка событий), вы можете достичь этого со следующим:
document.body.onfocus = function(){ /*rock it*/ }
Что приятно в этом, так это то, что вы можете присоединить/отсоединить его вовремя с событием файла, и он также отлично работает со скрытыми входами (определенный перк, если вы используете визуальный обходной путь для дрянной настройки по умолчанию input type='file'). После этого вам просто нужно выяснить, изменилось ли входное значение.
Пример:
var godzilla = document.getElementById('godzilla')
godzilla.onclick = charge
function charge()
{
document.body.onfocus = roar
console.log('chargin')
}
function roar()
{
if(godzilla.value.length) alert('ROAR! FILES!')
else alert('*empty wheeze*')
document.body.onfocus = null
console.log('depleted')
}
Смотрите в действии: http://jsfiddle.net/Shiboe/yuK3r/6/
К сожалению, он работает только в браузерах webkit. Возможно, кто-то еще может найти решение firefox/IE
Вы не можете.
Результат диалога с файлом не отображается в браузере.
/* Tested on Google Chrome */
$("input[type=file]").bind("change", function() {
var selected_file_name = $(this).val();
if ( selected_file_name.length > 0 ) {
/* Some file selected */
}
else {
/* No file selected or cancel/close
dialog button clicked */
/* If user has select a file before,
when they submit, it will treated as
no file selected */
}
});
Когда вы выбираете файл и открываете/отменяете, элемент input
должен терять фокус aka blur
. Предполагая, что начальный value
input
пуст, любое непустое значение в вашем обработчике blur
указывает на OK, а пустым значением будет "Отмена".
UPDATE: blur
не запускается, когда input
скрыт. Поэтому нельзя использовать этот трюк при загрузке на основе IFRAME, если вы не хотите временно отображать input
.
Вы можете уловить отмену, если вы выберете тот же файл, что и ранее, и нажмите "Отменить": в этом случае.
Вы можете сделать это следующим образом:
<input type="file" id="myinputfile"/>
<script>
document.getElementById('myinputfile').addEventListener('change', myMethod, false);
function myMethod(evt) {
var files = evt.target.files;
f= files[0];
if (f==undefined) {
// the user has clicked on cancel
}
else if (f.name.match(".*\.jpg")|| f.name.match(".*\.png")) {
//.... the user has choosen an image file
var reader = new FileReader();
reader.onload = function(evt) {
try {
myimage.src=evt.target.result;
...
} catch (err) {
...
}
};
}
reader.readAsDataURL(f);
</script>
Просто прослушайте событие click.
Следуя примеру Shiboe, здесь пример jQuery:
var godzilla = $('#godzilla');
var godzillaBtn = $('#godzilla-btn');
godzillaBtn.on('click', function(){
godzilla.trigger('click');
});
godzilla.on('change click', function(){
if (godzilla.val() != '') {
$('#state').html('You have chosen a Mech!');
} else {
$('#state').html('Choose your Mech!');
}
});
Вы можете увидеть это в действии здесь: http://jsfiddle.net/T3Vwz
Решение Shiboe было бы хорошим, если бы оно работало на мобильном webkit, но это не так. Я могу придумать, чтобы добавить прослушиватель событий mousemove к некоторому dom-объекту в то время, когда открывается окно ввода файла, например:
$('.upload-progress').mousemove(function() {
checkForFiles(this);
});
checkForFiles = function(me) {
var filefield = $('#myfileinput');
var files = filefield.get(0).files;
if (files == undefined || files[0] == undefined) $(me).remove(); // user cancelled the upload
};
Событие mousemove заблокировано со страницы, когда диалог файла открыт, и когда его закрытая проверяет, есть ли в файле файлы. В моем случае я хочу, чтобы индикатор активности блокировал вещи до тех пор, пока файл не будет загружен, поэтому я хочу только удалить свой индикатор при отмене.
Однако это не решает для мобильных устройств, поскольку мышь не движется. Мое решение там менее совершенное, но я считаю его достаточно хорошим.
$('.upload-progress').bind('touchstart', function() {
checkForFiles(this);
});
Теперь мы прислушиваемся к сенсорному экрану для проверки того же файла. Я довольно уверен, что пользовательский палец будет помещен на экран довольно быстро после отмены и отклонения этого индикатора активности.
Можно также просто добавить индикатор активности в событие изменения входного файла, но на мобильном телефоне часто происходит несколько секунд между выбором изображения и сменой события изменения, поэтому его намного лучше UX для индикатора активности отображается в начале процесса.
Большинство из этих решений не работают для меня.
Проблема в том, что вы никогда не знаете, какое событие будет вызвано кулаком,
это click
или это change
? Вы не можете принять какой-либо заказ, потому что он, вероятно, зависит от реализации браузера.
По крайней мере, в Opera и Chrome (конец 2015 года) click
запускается непосредственно перед "заполнением" ввода с файлами, поэтому вы никогда не узнаете длину files.length != 0
до тех пор, пока вы не запустите click
для запуска после change
.
Вот код:
var inputfile = $("#yourid");
inputfile.on("change click", function(ev){
if (ev.originalEvent != null){
console.log("OK clicked");
}
document.body.onfocus = function(){
document.body.onfocus = null;
setTimeout(function(){
if (inputfile.val().length === 0) console.log("Cancel clicked");
}, 1000);
};
});
В моем случае мне пришлось скрывать кнопку отправки, пока пользователи выбирали изображения.
Вот что я поднимаю:
$(document).on('click', '#image-field', function(e) {
$('.submit-button').prop('disabled', true)
})
$(document).on('focus', '#image-field'), function(e) {
$('.submit-button').prop('disabled', false)
})
#image-field
- это мой файловый селектор. Когда somenone нажимает на него, я отключу кнопку отправки формы. Дело в том, что когда диалог с файлом закрыт - неважно, что они выбирают файл или отменят - #image-field
получил фокус назад, поэтому я слушаю это событие.
UPDATE
Я обнаружил, что это не работает в safari и poltergeist/phantomjs. Учитывайте эту информацию, если вы хотите ее реализовать.
Объединяя решения Shiboe и alx, у меня самый надежный код:
var selector = $('<input/>')
.attr({ /* just for example, use your own attributes */
"id": "FilesSelector",
"name": "File",
"type": "file",
"contentEditable": "false" /* if you "click" on input via label, this prevents IE7-8 from just setting caret into file input text filed*/
})
.on("click.filesSelector", function () {
/* do some magic here, e.g. invoke callback for selection begin */
var cancelled = false; /* need this because .one calls handler once for each event type */
setTimeout(function () {
$(document).one("mousemove.filesSelector focusin.filesSelector", function () {
/* namespace is optional */
if (selector.val().length === 0 && !cancelled) {
cancelled = true; /* prevent double cancel */
/* that the point of cancel, */
}
});
}, 1); /* 1 is enough as we just need to delay until first available tick */
})
.on("change.filesSelector", function () {
/* do some magic here, e.g. invoke callback for successful selection */
})
.appendTo(yourHolder).end(); /* just for example */
Как правило, событие mousemove делает трюк, но в случае, если пользователь сделал клик и чем:
... мы не получим mousemove, следовательно, не отменим обратный вызов. Более того, если пользователь отменяет второй диалог и совершает движение мыши, мы получим 2 отмененных обратных вызова. К счастью, специальное событие jQuery focusIn в обоих случаях пузырится до документа, помогая нам избежать таких ситуаций. Единственное ограничение заключается в том, что один из них блокирует событие focusIn.
Я вижу, что мой ответ будет довольно устаревшим, но тем не менее. Я столкнулся с той же проблемой. Так вот мое решение. Самый полезный код, отрезанный, был KGA. Но он не совсем работает и немного сложнее. Но я упростил его.
Кроме того, основным создателем проблем был тот факт, что событие "change" не происходит сразу после фокуса, поэтому нам нужно подождать некоторое время.
"# appendfile" - пользователь нажимает, чтобы добавить новый файл. Hrefs получают фокусные события.
$("#appendfile").one("focusin", function () {
// no matter - user uploaded file or canceled,
// appendfile gets focus
// change doesn't come instantly after focus, so we have to wait for some time
// wrapper represents an element where a new file input is placed into
setTimeout(function(){
if (wrapper.find("input.fileinput").val() != "") {
// user has uploaded some file
// add your logic for new file here
}
else {
// user canceled file upload
// you have to remove a fileinput element from DOM
}
}, 900);
});
Вы можете обнаружить это только в ограниченных обстоятельствах. В частности, в chrome, если файл был выбран ранее, а затем щелкнул диалог файла и отменил щелчок, Chrome очистит файл и запускает событие onChange.
https://code.google.com/p/chromium/issues/detail?id=2508
В этом случае вы можете обнаружить это, обработав событие onChange и проверив свойство files.
Существует хакерский способ сделать это (добавьте обратные вызовы или разрешите выполнение отложенных/обещаний вместо вызовов alert()
):
var result = null;
$('<input type="file" />')
.on('change', function () {
result = this.files[0];
alert('selected!');
})
.click();
setTimeout(function () {
$(document).one('mousemove', function () {
if (!result) {
alert('cancelled');
}
});
}, 1000);
Как это работает: пока диалог выбора файла открыт, документ не получает события указателя мыши. Существует задержка в 1000 мс, чтобы диалоговое окно действительно отображалось и блокировало окно браузера. Проверено в Chrome и Firefox (только для Windows).
Но это не надежный способ обнаружить отмененный диалог, конечно. Хотя, может улучшить некоторые поведение пользовательского интерфейса для вас.
Вот мое решение, используя фокус ввода файла (не используя таймеры)
var fileInputSelectionInitiated = false;
function fileInputAnimationStart() {
fileInputSelectionInitiated = true;
if (!$("#image-selector-area-icon").hasClass("fa-spin"))
$("#image-selector-area-icon").addClass("fa-spin");
if (!$("#image-selector-button-icon").hasClass("fa-spin"))
$("#image-selector-button-icon").addClass("fa-spin");
}
function fileInputAnimationStop() {
fileInputSelectionInitiated = false;
if ($("#image-selector-area-icon").hasClass("fa-spin"))
$("#image-selector-area-icon").removeClass("fa-spin");
if ($("#image-selector-button-icon").hasClass("fa-spin"))
$("#image-selector-button-icon").removeClass("fa-spin");
}
$("#image-selector-area-wrapper").click(function (e) {
$("#fileinput").focus();
$("#fileinput").click();
});
$("#preview-image-wrapper").click(function (e) {
$("#fileinput").focus();
$("#fileinput").click();
});
$("#fileinput").click(function (e) {
fileInputAnimationStart();
});
$("#fileinput").focus(function (e) {
fileInputAnimationStop();
});
$("#fileinput").change(function(e) {
// ...
}
В лучшем случае это взломано, но вот рабочий пример моего решения, чтобы определить, загрузил ли пользователь файл, и только разрешить им продолжить, если они загрузили файл.
В основном скрыть Continue
, Save
, Proceed
или любую вашу кнопку. Затем в JavaScript вы получите имя файла. Если имя файла не имеет значения, не показывайте кнопку Continue
. Если у него есть значение, тогда покажите кнопку. Это также работает, если они сначала загружают файл, а затем пытаются загрузить другой файл и нажмите "Отменить".
Вот код.
HTML:
<div class="container">
<div class="row">
<input class="file-input" type="file" accept="image/*" name="fileUpload" id="fileUpload" capture="camera">
<label for="fileUpload" id="file-upload-btn">Capture or Upload Photo</label>
</div>
<div class="row padding-top-two-em">
<input class="btn btn-success hidden" id="accept-btn" type="submit" value="Accept & Continue"/>
<button class="btn btn-danger">Back</button>
</div></div>
JavaScript:
$('#fileUpload').change(function () {
var fileName = $('#fileUpload').val();
if (fileName != "") {
$('#file-upload-btn').html(fileName);
$('#accept-btn').removeClass('hidden').addClass('show');
} else {
$('#file-upload-btn').html("Upload File");
$('#accept-btn').addClass('hidden');
}
});
CSS
.file-input {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
.file-input + label {
font-size: 1.25em;
font-weight: normal;
color: white;
background-color: blue;
display: inline-block;
padding: 5px;
}
.file-input:focus + label,
.file-input + label:hover {
background-color: red;
}
.file-input + label {
cursor: pointer;
}
.file-input + label * {
pointer-events: none;
}
Для CSS многое из этого - сделать сайт и кнопку доступными для всех. Настройте свою кнопку так, как вам нравится.
Кажется, что для меня работает (на рабочем столе, в окнах):
var openFile = function (mimeType, fileExtension) {
var defer = $q.defer();
var uploadInput = document.createElement("input");
uploadInput.type = 'file';
uploadInput.accept = '.' + fileExtension + ',' + mimeType;
var hasActivated = false;
var hasChangedBeenCalled = false;
var hasFocusBeenCalled = false;
var focusCallback = function () {
if (hasActivated) {
hasFocusBeenCalled = true;
document.removeEventListener('focus', focusCallback, true);
setTimeout(function () {
if (!hasChangedBeenCalled) {
uploadInput.removeEventListener('change', changedCallback, true);
defer.resolve(null);
}
}, 300);
}
};
var changedCallback = function () {
uploadInput.removeEventListener('change', changedCallback, true);
if (!hasFocusBeenCalled) {
document.removeEventListener('focus', focusCallback, true);
}
hasChangedBeenCalled = true;
if (uploadInput.files.length === 1) {
//File picked
var reader = new FileReader();
reader.onload = function (e) {
defer.resolve(e.target.result);
};
reader.readAsText(uploadInput.files[0]);
}
else {
defer.resolve(null);
}
};
document.addEventListener('focus', focusCallback, true); //Detect cancel
uploadInput.addEventListener('change', changedCallback, true); //Detect when a file is picked
uploadInput.click();
hasActivated = true;
return defer.promise;
}
Это использует angularjs $q, но при необходимости вы можете заменить его любой другой платформой обещаний.
Протестировано на IE11, Edge, Chrome, Firefox, но, похоже, он не работает в Chrome на Android-планшета, так как он не запускает событие Focus.
Поле типа file
, к сожалению, не отвечает на множество событий (размытие было бы прекрасным). Я вижу много людей, предлагающих change
-ориентированные решения, и они получают downvoted.
change
работает, но у него есть главный недостаток (по сравнению с тем, что мы хотим).
При первой загрузке страницы, содержащей поле файла, откройте окно и нажмите "Отмена". Ничего, разочаровывающе, не меняется.
То, что я выбрал, - это загрузка в закрытом состоянии.
section#after-image
в моем случае скрыта от представления. Когда мой file field
изменяется, отображается кнопка загрузки. После успешной загрузки отображается section#after-image
.change
будет вызвано этой отменой, и там я смогу (и сделаю) снова скрыть мою кнопку загрузки до тех пор, пока не будет выбран правильный файл.Мне повезло, что это закрытое состояние уже было оформлением моей формы. Вам не нужно использовать один и тот же стиль, просто нажав кнопку загрузки и сменив ее, установив скрытое поле или переменную javascript на то, что вы можете отслеживать при отправке.
Я попытался изменить значение файлов [0], прежде чем поле было взаимодействовать. Это ничего не делало в отношении обмена.
Итак, да, change
работает, по крайней мере, так хорошо, как мы собираемся получить. Файловое поле защищено по понятным причинам, но к разочарованию благих намерений разработчиков.
Это не соответствует моей цели, но вы можете onclick
загружать предупреждение (а не alert()
, потому что это останавливает обработку страниц) и скрыть его, если смена инициирована и файлы [ 0] равно нулю. Если изменение не запускается, div остается в своем состоянии.
Я нашел этот атрибут, его самый простой пока.
if ($('#selectedFile')[0].files.length > 1)
{
// Clicked on 'open' with file
} else {
// Clicked on 'cancel'
}
Здесь selectedFile
является input type=file
.
Вы можете создать прослушиватель jquery change в поле ввода и обнаружить, что пользователь отменяет или закрывает окно загрузки по значению поля.
вот пример:
//when upload button change
$('#upload_btn').change(function(){
//get uploaded file
var file = this.files[0];
//if user choosed a file
if(file){
//upload file or perform your desired functiuonality
}else{
//user click cancel or close the upload window
}
});
Мне нужно было это сделать, и я создал очень простое решение. Здесь можно увидеть: http://jsfiddle.net/elizeubh2006/1w711q0y/5/
(Но будет работать только после первого выбора файла. Для меня это было полезно, потому что событие onchange вызывалось даже тогда, когда пользователь нажал кнопку cancel. Пользователь выбрал файл, затем щелкнул, чтобы выбрать другой файл, но отменил и он был вызван.)
$("#inputFileId").on("change", function() {
var x = document.getElementById('inputFileId');
if(x.files.length == 0)
{
alert('cancel was pressed');
}
else
{
alert(x.files[0].name);
}
});
Тип ввода = код файла:
onchange="if(this.files[0]!=undefined){ UploadImg(); }else{ alert('cancel'); }"