O evento de seleção de arquivo de entrada HTML não é acionado ao selecionar o mesmo arquivo


204

Existe alguma chance de detectar cada seleção de arquivo que o usuário fez para um HTML inputdo fileelemento type ?

Isso foi solicitado várias vezes antes, mas o onchangeevento geralmente proposto não é acionado se o usuário selecionar o mesmo arquivo novamente.


7
Seu código também teria que ser acionado se o usuário pressionar Cancelar? Espera-se que pressionar Cancelar não faça nada, e acho que a maioria dos usuários esperaria que a re-seleção do mesmo arquivo tivesse o mesmo efeito que Cancelar. Não sei se isso é possível ou não, mas sugiro que você reconsidere esse design de qualquer maneira.
KRyan #

1
Ao cancelar, ele não deve disparar ou torná-lo detectável. É mais importante remover um ceveat da interface do usuário: se alguma ação for chamada após a escolha do arquivo, o usuário normalmente espera que a ação se repita se ele escolher o arquivo novamente.
Dronus

Talvez possamos ter esse comportamento se definirmos o inputvalor s como '' depois de fazer algo com o arquivo. Mas isso removeria o nome do arquivo visível também. No entanto, isso pode ser bom, pois o arquivo é realmente processado e o resultado dessa ação pode aparecer em outro lugar.
dronus

Plz Explain the Que O que você quer fazer?
Champ

1
Tudo o que eu quero é simular o comportamento da velha escola que os aplicativos de desktop têm. Se eu 'abrir' o mesmo arquivo novamente em um aplicativo da área de trabalho, ele geralmente será recarregado ou se alguma ação for realizada com o arquivo (como convertê-lo em outro formato, por exemplo), essa ação será executada novamente. É o que os usuários de desktop também podem esperar de um aplicativo Web, mas o evento de fileentrada onchangenão se parece.
Dronus 24/08/12

Respostas:


279

Defina o valor de inputpara nullem cada onclickevento. Isso redefinirá o inputvalor do e disparará o onchangeevento, mesmo que o mesmo caminho esteja selecionado.

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

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

Aqui está uma demonstração .

Nota: É normal se o seu arquivo tiver o prefixo 'C: \ fakepath \'. Esse é um recurso de segurança que impede o JavaScript de conhecer o caminho absoluto do arquivo. O navegador ainda o conhece internamente.


1
Eu tentei a demonstração, mas (usando o Chrome 21) continuo recebendo `C: \ fakepath` + e o nome do arquivo que eu selecionei (excluindo o caminho). O alerta é exibido em todas as seleções do mesmo arquivo.
Jasper de Vries

1
@JasperdeVries Esse é um recurso de segurança que impede que o JavaScript saiba o caminho absoluto de um arquivo. O navegador ainda conhece o caminho internamente.
precisa saber é o seguinte

1
Como um aparte, null é o único valor permitido para <input type = "file">. Portanto, se você está tentando defini-lo como indefinido e obtendo uma exceção, essa é a razão.
precisa

5
Não funciona bem no IE11, a menos que você faça uma pequena alteração: demonstração .

21
É melhor colocar this.value = nullno final do texto onchangeporque é possível ativar um elemento de entrada sem clicar nele (usando o teclado). Você pode armazenar input.filesse precisar fazer referência posteriormente.
quer

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; só é necessário para o Chrome, o Firefox funcionará bem apenas com return false;

Aqui está um FIDDLE


2
simples e eficaz, testado apenas no IE e no Chrome mais recentes e funciona como um encanto. Obrigado por compartilhar
Atul Chaudhary

8

Neste artigo, sob o título "Usando entrada de formulário para selecionar"

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>

Ele adiciona um ouvinte de evento a 'alteração', mas eu o testei e é acionado mesmo se você escolher o mesmo arquivo e não se você cancelar.


Considerando o significado potencialmente ambíguo de "alteração" nesse caso, você tentou isso em vários navegadores? Você pode especificar quais os que experimentou na Web, os navegadores nem sempre estão em consenso sobre essas coisas.
precisa saber é o seguinte

2
Qual ambiente você usa para o seu teste? Minha experiência com o Chrome foi a que afirmei na pergunta; o changeevento seria acionado apenas nas alterações de nome de arquivo.
dronus

7

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

Obrigado pela solução.
Deepak Tekchandani

1

Faça o que você quiser depois que o arquivo for carregado com êxito. Logo após a conclusão do processamento do arquivo, defina o valor do controle de arquivo como string em branco. como por exemplo, você pode fazer isso e trabalhou para mim como charme

   $('#myFile').change(function () {
       LoadFile("myFile");//function to do processing of file.
       $('#myFile').val('');// set the value to empty of myfile control.
    });

1
handleChange({target}) {
    const files = target.files
    target.value = ''
}

1
Hey ngCourse! Respostas apenas de código podem resolver o problema, mas são muito mais úteis se você explicar como elas o resolvem. A comunidade requer teoria e código para entender sua resposta completamente.
RBT

Embora esse código possa resolver a questão, incluindo uma explicação de como e por que isso resolve o problema realmente ajudaria a melhorar a qualidade da sua postagem e provavelmente resultará em mais votos positivos. Lembre-se de que você está respondendo à pergunta dos leitores no futuro, não apenas à pessoa que está perguntando agora. Por favor edite sua resposta para adicionar explicações e dar uma indicação do que limitações e premissas se aplicam. Da avaliação
double-beep

1

Limpar o valor do 0º índice de entrada funcionou para mim . Por favor, tente o código abaixo, espero que funcione (AngularJs).

          scope.onClick = function() {
            input[0].value = "";
                input.click();
            };
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.