¿Cómo detectar cuando se hace clic en cancelar en la entrada del archivo?

¿Cómo puedo detectar cuándo el usuario cancela una entrada de archivo usando una entrada de archivo html?

onChange me permite detectar cuándo eligen un archivo, pero también me gustaría saber cuándo se cancelan (cierre el archivo y elija el diálogo sin seleccionar nada).

Aunque no es una solución directa, y también mala porque solo (por lo que he probado) funciona con onfocus (que requiere un locking de eventos bastante limitado) puede lograrlo con lo siguiente:

document.body.onfocus = function(){ /*rock it*/ } 

Lo bueno de esto es que puedes adjuntarlo / desacoplarlo a tiempo con el evento de archivo, y también parece funcionar bien con entradas ocultas (un beneficio definitivo si estás utilizando una solución visual para el tipo de entrada por defecto crappy = ‘ archivo’). Después de eso, solo necesita averiguar si el valor de entrada cambió.

Un ejemplo:

 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') } 

Véalo en acción: http://jsfiddle.net/Shiboe/yuK3r/6/

Lamentablemente, solo parece funcionar en los navegadores webkit. Tal vez alguien más pueda descubrir la solución de Firefox / IE

No puedes.

El resultado del diálogo de archivo no está expuesto al navegador.

 /* 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 */ } }); 

Cuando selecciona un archivo y hace clic en abrir / cancelar, el elemento de input debe perder el foco, también conocido como blur . Suponiendo que el value inicial de la input está vacío, cualquier valor no vacío en su controlador de blur indicaría un OK, y un valor vacío significaría un Cancelar.

ACTUALIZACIÓN: el blur no se activa cuando la input está oculta. Por lo tanto, no puede usar este truco con las cargas basadas en IFRAME, a menos que desee mostrar temporalmente la input .

Puede tomar la cancelación si elige el mismo archivo que anteriormente y hace clic en cancelar: en este caso.

Puedes hacerlo así:

   

Solo escuche el evento click también.

Siguiendo el ejemplo de Shiboe, aquí hay un ejemplo de 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!'); } }); 

Puedes verlo en acción aquí: http://jsfiddle.net/T3Vwz

La forma más fácil es verificar si hay algún archivo en la memoria temporal. Si desea obtener el evento de cambio cada vez que el usuario haga clic en la entrada del archivo, puede activarlo.

 var yourFileInput = $("#yourFileInput"); yourFileInput.on('mouseup', function() { $(this).trigger("change"); }).on('change', function() { if (this.files.length) { //User chose a picture } else { //User clicked cancel } }); 

La solución de Shiboe sería buena si funcionara en un webkit móvil, pero no es así. Lo que se me ocurre es agregar un detector de eventos mousemove a algún objeto dom en el momento en que se abre la ventana de entrada de archivos, así:

  $('.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 }; 

El evento mousemove está bloqueado desde la página mientras el cuadro de diálogo de archivo está abierto, y cuando se cierra comprueba si hay archivos en la entrada del archivo. En mi caso, quiero un indicador de actividad que bloquee las cosas hasta que se cargue el archivo, por lo que solo quiero eliminar mi indicador al cancelar.

Sin embargo, esto no se resuelve para dispositivos móviles, ya que no hay mouse para mover. Mi solución no es perfecta, pero creo que es lo suficientemente buena.

  $('.upload-progress').bind('touchstart', function() { checkForFiles(this); }); 

Ahora estamos escuchando un toque en la pantalla para hacer la misma verificación de archivos. Estoy bastante seguro de que el dedo del usuario se colocará en la pantalla bastante rápido después de cancelar y descartar este indicador de actividad.

También se podría agregar el indicador de actividad en el evento de cambio de entrada de archivo, pero en el móvil a menudo hay unos segundos de retraso entre seleccionar la imagen y el evento de cambio, por lo que es mucho mejor UX para que el indicador de actividad se muestre en el inicio del proceso.

La mayoría de estas soluciones no funcionan para mí.

El problema es que nunca se sabe qué evento se desencadenará puñetazo, ¿está haciendo click o es change ? No puede suponer ningún orden porque probablemente depende de la implementación del navegador.

Al menos en Opera y Chrome (finales de 2015) el click se activa justo antes de la entrada de ‘relleno’ con archivos, por lo que nunca sabrá la longitud de files.length != 0 hasta que demore el click para files.length != 0 después del change .

Aquí está el código:

 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); }; }); 

Sé que esta es una pregunta muy antigua, pero en caso de que ayude a alguien, al usar el evento onmousemove para detectar la cancelación, descubrí que era necesario probar dos o más de esos eventos en un corto espacio de tiempo. Esto se debía a que el navegador generaba eventos de movimiento únicos (Chrome 65) cada vez que se sacaba el cursor de la ventana de diálogo de selección de archivos y cada vez que se sacaba de la ventana principal y volvía a entrar. Un simple contador de eventos de movimiento del mouse junto con un tiempo de espera de corta duración para restablecer el contador de nuevo a cero funcionó una delicia.

En mi caso, tuve que ocultar el botón de enviar mientras los usuarios seleccionaban las imágenes.

Esto es lo que surge:

 $(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 es mi selector de archivos. Cuando somenone hace clic en él, desactivo el botón de envío de formulario. El punto es que cuando el cuadro de diálogo de archivo se cerró, no importa que seleccionen un archivo o cancelen, #image-field recuperó el foco, por lo que escucho ese evento.

ACTUALIZAR

Descubrí que esto no funciona en safari y poltergeist / phantomjs. Toma esta información en cuenta si deseas implementarla.

Combinando las soluciones de Shiboe y Alx, tengo el código más confiable:

 var selector = $('') .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's text filed*/ }) .on("click.filesSelector", function () { /* do some magic here, eg 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's 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, eg invoke callback for successful selection */ }) .appendTo(yourHolder).end(); /* just for example */ 

En general, el evento mousemove es el truco, pero en caso de que el usuario haga un clic y que:

  • canceló el diálogo de abrir archivo por la tecla de escape (sin mover el mouse), hizo otro clic exacto para abrir el diálogo de archivo nuevamente …
  • se cambió el foco a cualquier otra aplicación, que volvió al diálogo de abrir archivo del navegador y se cerró, que se volvió a abrir mediante la tecla enter o espacio …

… no obtendremos el evento Mousemove, por lo tanto, no cancelaremos la callback. Además, si el usuario cancela el segundo diálogo y mueve el mouse, obtendremos 2 devoluciones de llamada canceladas. Afortunadamente, el jQuery focusIn especial surge hasta el documento en ambos casos, lo que nos ayuda a evitar tales situaciones. La única limitación es si uno bloquea el evento FocusIn tampoco.

Veo que mi respuesta sería bastante anticuada, pero nunca menos. Me enfrenté con el mismo problema. Así que aquí está mi solución. El código más útil cortado fue el de KGA. Pero no funciona del todo y es un poco complicado. Pero lo simplifiqué.

Además, el principal generador de problemas fue ese hecho, ese evento de ‘cambio’ no ocurre inmediatamente después del enfoque, por lo que debemos esperar un tiempo.

“#appendfile”: el usuario hace clic para agregar un nuevo archivo. Hrefs obtienen eventos de enfoque.

 $("#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); }); 

Puedes detectar esto solo en circunstancias limitadas. Específicamente, en Chrome, si se seleccionó un archivo antes y luego se hace clic en el diálogo del archivo y se hace clic en cancelar, Chrome borra el archivo y activa el evento onChange.

https://code.google.com/p/chromium/issues/detail?id=2508

En este escenario, puede detectar esto manejando el evento onChange y verificando la propiedad de los archivos .

Lo siguiente parece funcionar para mí (en el escritorio, ventanas):

 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; } 

Esto usa angularjs $ q pero deberías poder reemplazarlo con cualquier otro framework prometedor si es necesario.

Probado en IE11, Edge, Chrome, Firefox, pero no parece funcionar en Chrome en una tableta Android, ya que no activa el evento Focus.

Así que voy a poner mi sombrero en esta pregunta ya que se me ocurrió una solución novedosa. Tengo una aplicación web progresiva que permite a los usuarios capturar fotos y videos y subirlos. Usamos WebRTC cuando es posible, pero recurrimos a los recolectores de archivos HTML5 para dispositivos con menos soporte * tos Tos de Safari *. Si está trabajando específicamente en una aplicación web móvil Android / iOS que utiliza la cámara nativa para capturar fotos / videos directamente, esta es la mejor solución que he encontrado.

La clave de este problema es que cuando la página se carga, el file es null , pero luego cuando el usuario abre el cuadro de diálogo y presiona “Cancelar”, el file sigue siendo null , por lo tanto, no “cambió”, por lo que no hay “cambio” evento se desencadena. Para los escritorios, esto no es tan malo porque la mayoría de las IU de escritorio no dependen de saber cuándo se invoca una cancelación, pero las UI móviles que abren la cámara para capturar una foto / video dependen mucho de saber cuándo se presiona una cancelación.

Originalmente utilicé el evento document.body.onfocus para detectar cuándo el usuario regresó del selector de archivos, y esto funcionó para la mayoría de los dispositivos, pero iOS 11.3 lo rompió ya que ese evento no se desencadena.

Concepto

Mi solución a esto es * shudder * para medir el tiempo de CPU para determinar si la página está actualmente en primer plano o en segundo plano. En los dispositivos móviles, el tiempo de procesamiento se le da a la aplicación que se encuentra en primer plano. Cuando una cámara es visible roba el tiempo de la CPU y baja la prioridad del navegador. Todo lo que tenemos que hacer es medir cuánto tiempo de procesamiento se le da a nuestra página, cuando se inicia la cámara, nuestro tiempo disponible disminuirá drásticamente. Cuando la cámara se cierra (ya sea cancelada o no), nuestro tiempo disponible aumenta repentinamente.

Implementación

Podemos medir la temporización de la CPU utilizando setTimeout() para invocar una callback en X milisegundos, y luego medir cuánto tiempo tardó en invocarla. El navegador nunca lo invocará exactamente después de X milisegundos, pero si es razonable cerrar, entonces debemos estar en primer plano. Si el navegador está muy lejos (más de 10 veces más lento de lo solicitado) entonces debemos estar en segundo plano. Una implementación básica de esto es así:

 function waitForCameraDismiss() { const REQUESTED_DELAY_MS = 25; const ALLOWED_MARGIN_OF_ERROR_MS = 25; const MAX_REASONABLE_DELAY_MS = REQUESTED_DELAY_MS + ALLOWED_MARGIN_OF_ERROR_MS; const MAX_TRIALS_TO_RECORD = 10; const triggerDelays = []; let lastTriggerTime = Date.now(); return new Promise((resolve) => { const evtTimer = () => { // Add the time since the last run const now = Date.now(); triggerDelays.push(now - lastTriggerTime); lastTriggerTime = now; // Wait until we have enough trials before interpreting them. if (triggerDelays.length < MAX_TRIALS_TO_RECORD) { window.setTimeout(evtTimer, REQUESTED_DELAY_MS); return; } // Only maintain the last few event delays as trials so as not // to penalize a long time in the camera and to avoid exploding // memory. if (triggerDelays.length > MAX_TRIALS_TO_RECORD) { triggerDelays.shift(); } // Compute the average of all trials. If it is outside the // acceptable margin of error, then the user must have the // camera open. If it is within the margin of error, then the // user must have dismissed the camera and returned to the page. const averageDelay = triggerDelays.reduce((l, r) => l + r) / triggerDelays.length if (averageDelay < MAX_REASONABLE_DELAY_MS) { // Beyond any reasonable doubt, the user has returned from the // camera resolve(); } else { // Probably not returned from camera, run another trial. window.setTimeout(evtTimer, REQUESTED_DELAY_MS); } }; window.setTimeout(evtTimer, REQUESTED_DELAY_MS); }); } 

Probé esto en una versión reciente de iOS y Android, sacando la cámara nativa estableciendo los atributos en el elemento .

   

Esto funciona en realidad mucho mejor de lo que esperaba. Ejecuta 10 pruebas al solicitar que se invoque un temporizador en 25 milisegundos. A continuación, mide cuánto tiempo tardó en invocarse, y si el promedio de 10 bashs es inferior a 50 milisegundos, suponemos que debemos estar en primer plano y que la cámara se ha ido. Si es mayor a 50 milisegundos, entonces aún debemos estar en segundo plano y debemos continuar esperando.

Algunos detalles adicionales

Utilicé setTimeout() lugar de setInterval() porque este último puede setInterval() cola múltiples invocaciones que se ejecutan inmediatamente una después de la otra. Esto podría boost drásticamente el ruido en nuestros datos, por lo que me quedé con setTimeout() a pesar de que es un poco más complicado hacerlo.

Estos números particulares funcionaron bien para mí, aunque he visto al menos una vez que la cámara se desconectó prematuramente. Creo que esto se debe a que la cámara puede tardar en abrirse, y el dispositivo puede ejecutar 10 pruebas antes de que realmente se quede en segundo plano. Agregar más pruebas o esperar unos 25-50 milisegundos antes de iniciar esta función puede ser una solución para eso.

Escritorio

Desafortunadamente, esto realmente no funciona para los navegadores de escritorio. En teoría, el mismo truco es posible ya que priorizan la página actual sobre las páginas de fondo. Sin embargo, muchos escritorios tienen recursos suficientes para mantener la página ejecutándose a toda velocidad, incluso cuando están en segundo plano, por lo que esta estrategia no funciona realmente en la práctica.

Soluciones alternativas

Una solución alternativa que no mucha gente menciona que FileList fue burlarse de FileList . Comenzamos con null en y luego, si el usuario abre la cámara y cancela regresa a null , lo cual no es un cambio y no se activará ningún evento. Una solución sería asignar un archivo ficticio al en el inicio de la página, por lo tanto, configurar a null sería un cambio que desencadenaría el evento apropiado.

Desafortunadamente, no hay manera oficial de crear una lista de FileList , y el elemento requiere una FileList en particular y no aceptará ningún otro valor además de null . Naturalmente, los objetos FileList no se pueden construir directamente, se FileList a un problema de seguridad anterior que aparentemente ya no es relevante. La única forma de obtener uno fuera de un elemento es utilizar un truco que copia y pega datos para simular un evento del portapapeles que puede contener un objeto FileList (básicamente estás fingiendo un drag-and-drop- evento de un archivo en su sitio web). Esto es posible en Firefox, pero no para iOS Safari, por lo que no era viable para mi caso de uso particular.

Navegadores, por favor ...

Huelga decir que esto es evidentemente ridículo. El hecho de que las páginas web tengan notificación cero de que un elemento de IU crítico ha cambiado es simplemente ridículo. Esto es realmente un error en la especificación, ya que nunca fue pensado para una UI de captura de medios de pantalla completa, y no desencadenar el evento de "cambio" es técnicamente específico.

Sin embargo , ¿los proveedores de navegadores pueden reconocer la realidad de esto? Esto podría resolverse con un nuevo evento "hecho" que se desencadena incluso cuando no se produce ningún cambio, o simplemente puede activar el "cambio" de todos modos. Sí, eso sería en contra de las especificaciones, pero es trivial para mí deduplicar un evento de cambio en el lado de JavaScript, pero fundamentalmente es imposible inventar mi propio evento "hecho". Incluso mi solución es realmente solo heurística, si no ofrecen garantías sobre el estado del navegador.

Tal como está, esta API es fundamentalmente inutilizable para dispositivos móviles, y creo que un cambio de navegador relativamente simple podría hacer que esto sea infinitamente más fácil para los desarrolladores web *.

Hay una forma tediosa de hacer esto (agregar devoluciones de llamadas o resolver alguna implementación diferida / prometedora en lugar de llamadas de alert() ):

 var result = null; $('') .on('change', function () { result = this.files[0]; alert('selected!'); }) .click(); setTimeout(function () { $(document).one('mousemove', function () { if (!result) { alert('cancelled'); } }); }, 1000); 

Cómo funciona: cuando el cuadro de diálogo de selección de archivos está abierto, el documento no recibe eventos de puntero del mouse. Hay una demora de 1000 ms para permitir que el diálogo aparezca realmente y bloquear la ventana del navegador. Controlado en Chrome y Firefox (solo Windows).

Pero esta no es una forma confiable de detectar un diálogo cancelado, por supuesto. Sin embargo, podría mejorar el comportamiento de UI para usted.

Aquí está mi solución, usando el enfoque de entrada de archivo (sin usar temporizadores)

 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) { // ... } 

Esto es raro en el mejor de los casos, pero aquí hay un ejemplo práctico de mi solución para detectar si un usuario ha subido un archivo o no, y solo les permite continuar si han subido un archivo.

Básicamente oculta el Continue , Save , Proceed o lo que sea que sea tu botón. Luego, en JavaScript, tomas el nombre del archivo. Si el nombre del archivo no tiene un valor, entonces no muestre el botón Continue . Si tiene un valor, entonces muestra el botón. Esto también funciona si primero cargan un archivo y luego intentan cargar un archivo diferente y hacen clic en cancelar.

Aquí está el código.

HTML:

 

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; } 

Para el CSS, gran parte de esto es hacer que el sitio web y el botón estén accesibles para todos. Ajuste su botón a lo que quiera.

El campo de tipo de file , frustrantemente, no responde a muchos eventos (el desenfoque sería encantador). Veo a mucha gente sugiriendo soluciones orientadas al change y que los rechacen.

change sí funciona, pero tiene un defecto importante (frente a lo que queremos que suceda).

Cuando recién carga una página que contiene un campo de archivo, abra la casilla y presione cancelar. Nada, frustrantemente, cambia .

Lo que elegí hacer es cargar en un estado cerrado.

  • La siguiente parte del formulario de una section#after-image en mi caso está oculto a la vista. Cuando mi file field cambia, se muestra un botón de carga. Tras la carga exitosa, se muestra la section#after-image .
  • Si el usuario carga, abre el diálogo de archivo, luego cancela, nunca ve el botón de carga.
  • Si el usuario elige un archivo, se muestra el botón de carga. Si luego abren el diálogo y cancelan, el evento de change se desencadena por esta cancelación, y allí puedo (y lo hago) volver a ocultar mi botón de carga hasta que se seleccione un archivo adecuado.

Tuve la suerte de que este estado cerrado ya era el diseño de mi formulario. No es necesario que use el mismo estilo, simplemente tiene el botón de carga inicialmente oculto y, luego del cambio, establece un campo oculto o una variable de JavaScript en algo que puede supervisar al enviar.

Traté de cambiar el valor de los archivos [0] antes de que interactuara el campo. Esto no hizo nada con respecto al cambio.

Entonces sí, el change funciona, al menos tan bien como lo vamos a conseguir. El archivo está seguro, por razones obvias, pero para la frustración de los desarrolladores bien intencionados.

No es adecuado para mi propósito, pero es posible que, al hacer onclick , cargue un aviso de advertencia (no una alert() , porque eso interrumpe el procesamiento de la página), y lo oculte si se activa el cambio y los archivos [0] son ​​nulos. Si el cambio no se desencadena, el div permanece en su estado.

Bueno, esto no responde exactamente a tu pregunta. Mi suposición es que, tiene un escenario, cuando agrega una entrada de archivo, e invoca la selección de archivos, y si el usuario hace clic en cancelar, simplemente elimina la entrada.

Si este es el caso, entonces: ¿Por qué agregar una entrada de archivo vacía?

Crea el sobre la marcha, pero agrégalo a DOM solo cuando esté completo. De esta forma:

  var fileInput = $(""); fileInput.bind("change", function() { if (fileInput.val() !== null) { // if has value add it to DOM $("#files").append(fileInput); } }).click(); 

Así que aquí creo sobre la marcha, me sumo a su evento de cambio e inmediatamente invoco click. El cambio se activará solo cuando el usuario seleccione un archivo y presione Aceptar; de lo contrario, la entrada no se agregará al DOM, por lo tanto, no se enviará.

Ejemplo de trabajo aquí: https://jsfiddle.net/69g0Lxno/3/

// Usa el mouse en lugar de desenfocar

 var fileInput = $("#fileInput"); if (fileInput.is(":hover") { //open } else { } 
 function file_click() { document.body.onfocus = () => { setTimeout(_=>{ let file_input = document.getElementById('file_input'); if (!file_input.value) alert('please choose file ') else alert(file_input.value) document.body.onfocus = null },100) } } 

Usando setTimeout para obtener el cierto valor de la entrada.

Encontré este atributo, es el más simple hasta ahora.

 if ($('#selectedFile')[0].files.length > 1) { // Clicked on 'open' with file } else { // Clicked on 'cancel' } 

Aquí, selectedFile es un input type=file .

You can make a jquery change listener on the input field and detect that user cancel or closed upload window by the value of the field.

here is an example:

 //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 } }); 

I needed to do it and I ended up creating a very simple solution. Can be seen here: http://jsfiddle.net/elizeubh2006/1w711q0y/5/

(But will only work after a first file selection has occurred. For me it was useful because the onchange event was being called even when the user clicked cancel. The user chose a file, then clicked to select another file, but canceled and the onchange was called.)

  $("#inputFileId").on("change", function() { var x = document.getElementById('inputFileId'); if(x.files.length == 0) { alert('cancel was pressed'); } else { alert(x.files[0].name); } }); 

input type=file code:

 onchange="if(this.files[0]!=undefined){ UploadImg(); }else{ alert('cancel'); }"