El evento de selección del archivo de entrada HTML no se activa al seleccionar el mismo archivo

204

¿Hay alguna posibilidad de detectar cada selección de archivo que el usuario hizo para un elemento HTML inputde tipo file?

Esto se preguntó muchas veces antes, pero el onchangeevento generalmente propuesto no se dispara si el usuario selecciona el mismo archivo nuevamente.

Dronus
fuente
77
¿Tu código también debería activarse si el usuario presiona Cancelar? Uno espera que presionar Cancelar no haga nada, y creo que la mayoría de los usuarios esperarían que volver a seleccionar el mismo archivo tuviera el mismo efecto que Cancelar. No sé si esto es posible o no, pero le sugiero que reconsidere este diseño de todos modos.
KRyan
1
Al cancelar, no debe dispararse ni hacerlo detectable. Está más destinado a eliminar un ceveat de IU: si se invoca una acción después de elegir el archivo, el usuario generalmente espera que la acción se repita si elige el archivo nuevamente.
dronus
Tal vez podamos tener este comportamiento si establecemos el inputvalor de s en '' después de hacer algo con el archivo. Pero eso también eliminaría el nombre de archivo visible. Sin embargo, eso puede estar bien, ya que el archivo se procesa realmente y el resultado de esa acción puede aparecer en otro lugar.
dronus
Por favor, explique que ¿Qué quiere hacer?
Campeón el
1
Todo lo que quiero es simular el comportamiento de la vieja escuela que tienen las aplicaciones de escritorio. Si vuelvo a "abrir" el mismo archivo en una aplicación de escritorio, generalmente se vuelve a cargar, o si se realiza alguna acción con el archivo (como convertirlo en otro formato, por ejemplo), esta acción se realiza nuevamente. Esto es lo que los usuarios de escritorio pueden esperar de una aplicación web también, pero el evento de fileentrada onchangeno se parece.
Dronus

Respuestas:

279

Establezca el valor de inputa nullen cada onclickevento. Esto restablecerá el inputvalor de 's y activará el onchangeevento incluso si se selecciona la misma ruta.

input.onclick = function () {
    this.value = null;
};

input.onchange = function () {
    alert(this.value);
};​

Aquí hay una DEMO .

Nota: es normal si su archivo tiene el prefijo 'C: \ fakepath \'. Esa es una característica de seguridad que impide que JavaScript conozca la ruta absoluta del archivo. El navegador aún lo sabe internamente.

Brian Ustas
fuente
1
Probé la demostración, pero (usando Chrome 21) sigo obteniendo `C: \ fakepath` + luego el nombre de archivo que seleccioné (excluyendo la ruta). Sin embargo, la alerta se muestra en cada selección del mismo archivo.
Jasper de Vries
1
@JasperdeVries Esa es una característica de seguridad que impide que JavaScript conozca la ruta absoluta de un archivo. El navegador aún conoce la ruta internamente.
Brian Ustas
1
Por otro lado, nulo es el único valor permitido para <input type = "file">. Entonces, si está tratando de configurarlo como indefinido y obtener una excepción, esa es la razón.
Noel Abrahams
55
No funciona bien en IE11 a menos que haga un pequeño cambio: demo .
21
Es mejor ponerlo this.value = nullal final onchangeporque es posible activar un elemento de entrada sin hacer clic en él (usando el teclado). Puede almacenar input.filessi necesita consultarlo más tarde.
Halcyon
24
<form enctype='multipart/form-data'>
    <input onchange="alert(this.value); this.value=null; return false;" type='file'>
    <br>
    <input type='submit' value='Upload'>
</form>

this.value=null; solo es necesario para Chrome, Firefox funcionará bien solo con return false;

Aquí hay un violín

elshnkhll
fuente
2
simple y efectivo que acaba de probarse en el último IE y Chrome y funciona de maravilla. Gracias por compartirlo
Atul Chaudhary
8

En este artículo, bajo el título "Uso de entrada de formulario para seleccionar"

http://www.html5rocks.com/en/tutorials/file/dndfiles/

<input type="file" id="files" name="files[]" multiple />

<script>
function handleFileSelect(evt) {

    var files = evt.target.files; // FileList object

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
     // Code to execute for every file selected
    }
    // Code to execute after that

}

document.getElementById('files').addEventListener('change', 
                                                  handleFileSelect, 
                                                  false);
</script>

Agrega un detector de eventos para 'cambiar', pero lo probé y se dispara incluso si elige el mismo archivo y no si cancela.

Xacur Aphrantus
fuente
Teniendo en cuenta el significado potencialmente ambiguo de "cambio" en este caso, ¿lo intentó en varios navegadores? Es posible que desee especificar en cuáles lo probó en la web, los navegadores no siempre están exactamente de acuerdo sobre estas cosas.
Thor84no
2
¿Qué entorno utilizas para tu prueba? Mi experiencia con Chrome fue la que dije en la pregunta, el changeevento solo se dispararía en los cambios de nombre de archivo.
dronus
7

Use el evento onClick para borrar el valor de la entrada objetivo, cada vez que el usuario hace clic en el campo. Esto asegura que el evento onChange se activará también para el mismo archivo. Trabajó para mi :)

onInputClick = (event) => {
    event.target.value = ''
}

<input type="file" onChange={onFileChanged} onClick={onInputClick} />

Usando TypeScript

onInputClick = ( event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
    const element = event.target as HTMLInputElement
    element.value = ''
}
Ley de Trafalgar
fuente
Gracias por la solucion.
Deepak Tekchandani
1

Haga lo que quiera hacer después de que el archivo se cargue correctamente. Justo después de completar el procesamiento de su archivo, establezca el valor del control de archivo en una cadena en blanco. Entonces, el .change () siempre se llamará incluso si el nombre del archivo cambia o no. por ejemplo, puedes hacer esto y funcionó para mí como encanto

   $('#myFile').change(function () {
       LoadFile("myFile");//function to do processing of file.
       $('#myFile').val('');// set the value to empty of myfile control.
    });
Mohit Singh
fuente
1
handleChange({target}) {
    const files = target.files
    target.value = ''
}
Shashwat Gupta
fuente
1
Hola ngCurso! Las respuestas de solo código pueden resolver el problema, pero son mucho más útiles si explica cómo lo resuelven. La comunidad requiere tanto teoría como código para comprender su respuesta por completo.
RBT
Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación, y probablemente resultaría en más votos positivos. Recuerde que está respondiendo la pregunta para los lectores en el futuro, no solo la persona que pregunta ahora. Por favor, editar su respuesta para agregar explicaciones y dar una indicación de lo que se aplican limitaciones y supuestos. De la opinión
doble pitido
1

Borrar el valor del índice 0 de entrada funcionó para mí . Por favor, intente el siguiente código, espero que esto funcione (AngularJs).

          scope.onClick = function() {
            input[0].value = "";
                input.click();
            };
Dilip Kumar
fuente