¿Cómo detectar input type = file "change" para el mismo archivo?

131

Quiero activar un evento cuando el usuario selecciona un archivo. Hacerlo con .changeevento funciona si el usuario cambia el archivo cada vez.

Pero quiero activar el evento si el usuario selecciona el mismo archivo nuevamente.

  1. Archivo de selección de usuario A.jpg(evento de incendios)
  2. Archivo de selección de usuario B.jpg(evento de incendios)
  3. Archivo de selección de usuario B.jpg(el evento no se dispara, quiero que se dispare)

¿Cómo puedo hacerlo?

Gadonski
fuente

Respuestas:

78

Puedes engañarlo. Elimine el elemento del archivo y agréguelo en el mismo lugar en el changeevento. Borrará la ruta del archivo haciéndolo cambiante cada vez.

Ejemplo en jsFiddle.

O simplemente puede usar .prop("value", ""), vea este ejemplo en jsFiddle .

  • jQuery 1.6+ prop
  • Versiones anteriores attr
BrunoLM
fuente
@Pekka: No exactamente. Pero él solo puede adaptarlo. Digamos que necesita publicar el archivo. Después de la publicación, puede llamar a una función js que eliminará y agregará el nuevo selector de archivos. Es factible.
BrunoLM
3
tenga en cuenta que cuando use .attr("value", "")o .val("")(como lo sugiere @ wagner-leonardi a continuación), Internet Explorer disparará el evento de cambio mientras Chrome no lo haga
fadomire
44
dado que "valor" es una propiedad y no un atributo de entrada, el uso recomendado de jQuery sería.prop("value", "")
Roger Barreto
70

Si lo ha intentado .attr("value", "")y no funcionó, no se asuste (como lo hice)

solo hazlo .val(""), y funcionará bien

Wagner Leonardi
fuente
49

Simplemente puede establecer que la ruta del archivo sea nula cada vez que el usuario hace clic en el control. Ahora, incluso si el usuario selecciona el mismo archivo, se activará el evento onchange .

<input id="file" onchange="file_changed(this)" onclick="this.value=null;" type="file" accept="*/*" />
Mariusz Wiazowski
fuente
2
Necesitaba una solución como esta. Es realmente corto y hace el trabajo. Buen pensamiento Mariusz Wiazowski.
Jay Dharmendra Solanki el
Otra solución es ese valor cambiante cuando cambia la etiqueta de entrada. Pero no esperamos que el valor cambie después de seleccionar un archivo.
songgeb
1
Genial, mucho mejor que quitar y agregar el elemento en el dom nuevamente, gracias
David Dal Busco
24

Use el evento onClick para borrar el valor de la entrada objetivo, cada vez que el usuario hace clic en el campo. Esto garantiza 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
17

Conseguí que esto funcionara borrando el valor de entrada del archivo en Haga clic y luego publicando el archivo en Cambiar. Esto le permite al usuario seleccionar el mismo archivo dos veces seguidas y aún así activar el evento de cambio para publicarlo en el servidor. Mi ejemplo utiliza el complemento de formulario jQuery .

$('input[type=file]').click(function(){
    $(this).attr("value", "");
})  
$('input[type=file]').change(function(){
    $('#my-form').ajaxSubmit(options);      
})
Braitsch
fuente
onClickdispara antes onChange, por lo que este método funciona muy bien para mí.
iplus26
8

Este trabajo para mi

<input type="file" onchange="function();this.value=null;return false;">

fuente
1
Supongo que querías decir algo como function () {this.value = null; falso retorno; }
Jacek Pietal
7

Solución VueJs

<input
                type="file"
                style="display: none;"
                ref="fileInput"
                accept="*"
                @change="onFilePicked"
                @click="$refs.fileInput.value=null"
>
Micheal C Wallas
fuente
1
Gracias por esta respuesta variante
Coisox
5

Inspirador de @braitsch, he usado lo siguiente en mi AngularJS2 input-file-component

<input id="file" onclick="onClick($event) onchange="onChange($event)" type="file" accept="*/*" />

export class InputFile {

    @Input()
    file:File|Blob;

    @Output()
    fileChange = new EventEmitter();

    onClick(event) {
        event.target.value=''
    }
    onChange(e){
        let files  = e.target.files;
        if(files.length){
            this.file = files[0];
        }
        else { this.file = null}
        this.fileChange.emit(this.file);
    }
}

Aquí onClick(event)me rescataron :-)

MKJ
fuente
3

Probablemente lo más fácil que puede hacer es establecer el valor en una cadena vacía. Esto lo obliga a 'cambiar' el archivo cada vez, incluso si el mismo archivo se selecciona nuevamente.

<input type="file" value="" />

Brusco
fuente
3

Aquí está la solución React-y que he encontrado que funcionó para mí:

onClick={event => event.target.value = null}

Heckmann
fuente
2

Si no quieres usar jQuery

<form enctype='multipart/form-data'>
    <input onchange="alert(this.value); return false;" type='file'>
    <br>
    <input type='submit' value='Upload'>
</form>

Funciona bien en Firefox, pero para Chrome debe agregar this.value=null;después de la alerta.

elshnkhll
fuente
2

Por defecto, la propiedad de valor del elemento de entrada se borra después de la selección de archivos si la entrada tiene múltiples atributos. Si no limpia esta propiedad, el evento "cambiar" no se activará si selecciona el mismo archivo. Puede administrar este comportamiento usando el multipleatributo.

<!-- will be cleared -->
<input type="file" onchange="yourFunction()" multiple/>
<!-- won't be cleared -->
<input type="file" onchange="yourFunction()"/>

Referencia

Pulkit Aggarwal
fuente
1

No puedes hacer changefuego aquí (comportamiento correcto, ya que nada ha cambiado). Sin embargo, también podrías unirte click... aunque esto puede disparar con demasiada frecuencia ... sin embargo, no hay mucho terreno intermedio entre los dos.

$("#fileID").bind("click change", function() {
  //do stuff
});
Nick Craver
fuente
Parece que solo estás repitiendo sus palabras y .click()no estás "disparando en la re-selección".
BrunoLM
@BrunoLM - No, no lo es ... pero creo que leíste la parte donde digo que no puedes hacer esto, clickestá lo más cerca posible.
Nick Craver
1

Cree para la entrada un evento de clic y un evento de cambio. El evento click vacía la entrada y el evento change contiene el código que desea ejecutar.

Por lo tanto, el evento de clic se vaciará cuando haga clic en el botón de entrada (antes de que se abra la ventana de selección de archivo), por lo que el evento de cambio siempre se activará cuando seleccione un archivo.

$("#input").click(function() {
  $("#input").val("")
});

$("#input").change(function() {
  //Your code you want to execute!
});
<input id="input" type="file">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>

hoi ja
fuente
0

Puede usar form.reset()para borrar la fileslista de entrada de archivos . Esto restablecerá todos los campos a los valores predeterminados, pero en muchos casos es posible que solo use el tipo de entrada = 'archivo' en un formulario para cargar archivos de todos modos. En esta solución no hay necesidad de clonar el elemento y volver a conectar eventos nuevamente.

Gracias a philiplehmann

Rui Nunes
fuente
0

Me encontré con el mismo problema, analicé las soluciones anteriores, pero no obtuvieron una buena explicación de lo que realmente estaba sucediendo.

Esta solución escribí https://jsfiddle.net/r2wjp6u8/ no hace muchos cambios en el árbol DOM, solo cambia los valores del campo de entrada. Desde el aspecto del rendimiento, debería ser un poco mejor.

Enlace al violín: https://jsfiddle.net/r2wjp6u8/

<button id="btnSelectFile">Upload</button>

<!-- Not displaying the Inputfield because the design changes on each browser -->
<input type="file" id="fileInput" style="display: none;">
<p>
  Current File: <span id="currentFile"></span>
</p>
<hr>
<div class="log"></div>


<script>
// Get Logging Element
var log = document.querySelector('.log');

// Load the file input element.
var inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', currentFile);

// Add Click behavior to button
document.getElementById('btnSelectFile').addEventListener('click', selectFile);

function selectFile() {
  if (inputElement.files[0]) {
    // Check how manyf iles are selected and display filename
    log.innerHTML += '<p>Total files: ' + inputElement.files.length + '</p>'
    // Reset the Input Field
    log.innerHTML += '<p>Removing file: ' + inputElement.files[0].name + '</p>'
    inputElement.value = '';
    // Check how manyf iles are selected and display filename
    log.innerHTML += '<p>Total files: ' + inputElement.files.length + '</p>'
    log.innerHTML += '<hr>'
  }

  // Once we have a clean slide, open fiel select dialog.
  inputElement.click();
};

function currentFile() {
    // If Input Element has a file
  if (inputElement.files[0]) {
    document.getElementById('currentFile').innerHTML = inputElement.files[0].name;
  }
}

</scrip>
Ballpin
fuente
0

Por lo tanto, no hay forma de asegurarse al 100% de que están seleccionando el mismo archivo a menos que almacene cada archivo y los compare mediante programación.

La forma en que interactúa con los archivos (lo que hace JS cuando el usuario 'carga' un archivo) es HTML5 File API y JS FileReader .

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

https://scotch.io/tutorials/use-the-html5-file-api-to-work-with-files-locally-in-the-browser

Estos tutoriales le muestran cómo capturar y leer los metadatos (almacenados como objeto js) cuando se carga un archivo.

Cree una función que active 'onChange' que leerá-> almacenar-> comparar metadatos del archivo actual con los archivos anteriores. Entonces puede activar su evento cuando se selecciona el archivo deseado.

Stephanie Schellin
fuente
0

¡Créeme, definitivamente te ayudará!

// there I have called two `onchange event functions` due to some different scenario processing.

<input type="file" class="selectImagesHandlerDialog" 
    name="selectImagesHandlerDialog" 
    onclick="this.value=null;" accept="image/x-png,image/gif,image/jpeg" multiple 
    onchange="delegateMultipleFilesSelectionAndOpen(event); disposeMultipleFilesSelections(this);" />


// delegating multiple files select and open
var delegateMultipleFilesSelectionAndOpen = function (evt) {

  if (!evt.target.files) return;

  var selectedPhotos = evt.target.files;
  // some continuous source

};


// explicitly removing file input value memory cache
var disposeMultipleFilesSelections = function () {
  this.val = null;
};

Espero que esto ayude a muchos de ustedes.

ArifMustafa
fuente