Como detectar entrada type = file "change" para o mesmo arquivo?

131

Quero disparar um evento quando o usuário selecionar um arquivo. Fazendo isso com.change evento funcionará se o usuário alterar o arquivo toda vez.

Mas quero disparar o evento se o usuário selecionar o mesmo arquivo novamente.

  1. Arquivo de seleção do usuário A.jpg(evento disparado)
  2. Arquivo de seleção do usuário B.jpg(evento disparado)
  3. Arquivo de seleção do usuário B.jpg(o evento não é acionado, quero que seja acionado)

Como eu posso fazer isso?

Gadonski
fonte

Respostas:

78

Você pode enganá-lo. Remova o elemento do arquivo e adicione-o no mesmo local do changeevento. Ele apagará o caminho do arquivo, tornando-o sempre mutável.

Exemplo em jsFiddle.

Ou você pode simplesmente usar .prop("value", ""), veja este exemplo no jsFiddle .

  • jQuery 1.6+ prop
  • Versões recentes attr
BrunoLM
fonte
@Pekka: Não exatamente. Mas ele pode apenas adaptá-lo. Digamos que ele precise publicar o arquivo. Após a postagem, ele pode chamar uma função js que removerá e adicionará o novo seletor de arquivos. É factível.
BrunoLM
3
estar ciente de que quando você usa .attr("value", "")ou .val("")(como sugerido por @ wagner-leonardi abaixo) Internet Explorer irá disparar o evento de alteração enquanto o Chrome não
fadomire
4
uma vez que "valor" é uma propriedade e não um atributo de entrada, o uso jQuery recomendado seria.prop("value", "")
Roger Barreto
70

Se você tentou .attr("value", "")e não funcionou, não entre em pânico (como eu fiz)

basta fazê-lo .val("")e funcionará bem

Wagner Leonardi
fonte
49

Você pode simplesmente definir como nulo o caminho do arquivo sempre que o usuário clicar no controle. Agora, mesmo que o usuário selecione o mesmo arquivo, o evento onchange será acionado.

<input id="file" onchange="file_changed(this)" onclick="this.value=null;" type="file" accept="*/*" />
Mariusz Wiazowski
fonte
2
Eu precisava de uma solução como esta. É realmente curto e faz o trabalho. Bom pensamento, Mariusz Wiazowski.
Jay Dharmendra Solanki
Outra solução é mudar o valor quando a tag de entrada foi alterada. Mas não esperamos que o valor seja alterado após selecionar um arquivo.
Songgeb 13/03/19
1
Cool, muito melhor do que remover e adicionar o elemento no DOM novamente, thx
David Dal Busco
24

Use o evento onClick para limpar o valor da entrada de destino, sempre que o usuário clicar no campo. Isso garante que o evento onChange seja acionado para o mesmo arquivo também. Trabalhou para mim :)

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 = ''
}
Trafalgar Law
fonte
17

Consegui que isso funcionasse limpando o valor de entrada do arquivo onClick e publicando o arquivo em Change. Isso permite que o usuário selecione o mesmo arquivo duas vezes seguidas e ainda tenha o acionamento do evento de alteração para postar no servidor. Meu exemplo usa o plugin do formulário jQuery .

$('input[type=file]').click(function(){
    $(this).attr("value", "");
})  
$('input[type=file]').change(function(){
    $('#my-form').ajaxSubmit(options);      
})
Braitsch
fonte
onClickdispara antes onChange, então esse método funciona muito bem para mim.
precisa saber é o seguinte
8

Esse trabalho pra mim

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

fonte
1
Eu acho que você quis dizer algo como function () {this.value = null; retorna falso; }
Jacek Pietal
7

Solução VueJs

<input
                type="file"
                style="display: none;"
                ref="fileInput"
                accept="*"
                @change="onFilePicked"
                @click="$refs.fileInput.value=null"
>
Micheal C Wallas
fonte
1
Obrigado por esta resposta variação
Coisox
5

Inspirando em @braitsch, usei o seguinte no meu 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);
    }
}

Aqui o onClick(event)me resgatou :-)

MKJ
fonte
3

Provavelmente, a coisa mais fácil que você pode fazer é definir o valor como uma sequência vazia. Isso obriga a 'alterar' o arquivo sempre que o mesmo arquivo for selecionado novamente.

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

Curt
fonte
3

Aqui está a solução React-y way que eu achei que funcionou para mim:

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

Heckmann
fonte
2

Se você não quiser usar o jQuery

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

Funciona bem no Firefox, mas para o Chrome você precisa adicionar um this.value=null;alerta.

elshnkhll
fonte
2

Por padrão, a propriedade value do elemento de entrada é limpa após a seleção dos arquivos, se a entrada tiver vários atributos. Se você não limpar esta propriedade, o evento "change" não será acionado se você selecionar o mesmo arquivo. Você pode gerenciar esse comportamento usando o multipleatributo

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

Referência

Pulkit Aggarwal
fonte
1

Você não pode fazer changefogo aqui (comportamento correto, pois nada mudou). No entanto, você também pode ligar click... embora isso possa disparar com muita frequência ... embora não haja muito meio termo entre os dois.

$("#fileID").bind("click change", function() {
  //do stuff
});
Nick Craver
fonte
Parece que você está apenas repetindo as palavras dele e .click()não está "disparando ao selecionar novamente".
BrunoLM
@BrunoLM - Não, não é ... mas acho que você leu a parte em que digo que não pode fazer isso, o clickmais próximo possível.
Nick Craver
1

Crie para a entrada um evento de clique e um evento de alteração. O evento click esvazia a entrada e o evento change contém o código que você deseja executar.

Portanto, o evento click ficará vazio quando você clicar no botão de entrada (antes da janela de seleção de arquivo abrir); portanto, o evento change será sempre acionado quando você selecionar um arquivo.

$("#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
fonte
0

Você pode usar form.reset()para limpar a fileslista de entradas do arquivo . Isso redefinirá todos os campos para os valores padrão, mas em muitos casos você pode usar apenas o tipo de entrada = 'arquivo' em um formulário para fazer upload de arquivos de qualquer maneira. Nesta solução, não há necessidade de clonar o elemento e reconectar os eventos novamente.

Graças a philiplehmann

Rui Nunes
fonte
0

Corri para o mesmo problema, encontrei as soluções acima, mas elas não obtiveram nenhuma explicação boa sobre o que realmente estava acontecendo.

Esta solução que escrevi https://jsfiddle.net/r2wjp6u8/ não faz muitas alterações na árvore DOM, apenas altera os valores do campo de entrada. Do aspecto desempenho, deve ser um pouco melhor.

Link para o violino: 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
fonte
0

Portanto, não há como 100% garantir que eles estejam selecionando o mesmo arquivo, a menos que você armazene cada arquivo e compare-os programaticamente.

A maneira como você interage com os arquivos (o que JS faz quando o usuário 'envia' um arquivo) é a API de arquivos HTML5 e o 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

Esses tutoriais mostram como capturar e ler os metadados (armazenados como objeto js) quando um arquivo é carregado.

Crie uma função que dispara 'onChange' que leia-> armazene-> compare os metadados do arquivo atual com os arquivos anteriores. Em seguida, você pode acionar seu evento quando o arquivo desejado for selecionado.

Stephanie Schellin
fonte
0

Acredite, definitivamente ajudará!

// 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 isso ajude muitos de vocês.

ArifMustafa
fonte