Limpando <input type = 'file' /> usando jQuery


Respostas:


529

Fácil: envolva um <form>elemento, chame reset no formulário e remova o formulário usando .unwrap(). Diferente das .clone()soluções de outra forma nesse encadeamento, você acaba com o mesmo elemento no final (incluindo propriedades customizadas que foram definidas nele).

Testado e trabalhando em Opera, Firefox, Safari, Chrome e IE6 +. Também funciona em outros tipos de elementos de formulário, com exceção de type="hidden".

window.reset = function(e) {
  e.wrap('<form>').closest('form').get(0).reset();
  e.unwrap();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form>
  <input id="file" type="file">
  <br>
  <input id="text" type="text" value="Original">
</form>

<button onclick="reset($('#file'))">Reset file</button>
<button onclick="reset($('#text'))">Reset text</button>

JSFiddle

Como o Timo observa abaixo, se você tiver os botões para acionar a redefinição do campo dentro do campo <form>, deverá chamar .preventDefault()o evento para impedir que o <button>envio seja acionado .


EDITAR

Não funciona no IE 11 devido a um erro não corrigido. O texto (nome do arquivo) é limpo na entrada, mas sua Filelista permanece preenchida.


14
Vencedora! Funciona em todos os navegadores e evita a clonagem do campo de entrada. Mas se os botões claros estiverem dentro do formulário, renomeie reset()para eg. reset2(), porque pelo menos no Chrome todos os campos são limpos, se estiverem reset(). E adicione event.preventDefault () depois de limpar a chamada para impedir o envio. Desta forma: <button onclick="reset2($('#file'));event.preventDefault()">Reset file</button>. Exemplo de trabalho: jsfiddle.net/rPaZQ/23 .
Timo Kähkönen 25/03

28
O problema é que isso, pelo menos temporariamente, torna o documento inválido. (Os formulários não podem conter outros formulários.) Se atualmente funciona ou não, é livre para interromper a hora que desejar.
cHao

6
@cHao, é claro que isso só é verdade se o elemento de entrada estiver realmente em um formulário, o que não precisa ser.
Ninjakannon

7
Em relação a ter um formulário em um formulário, você sempre pode criar um novo elemento de formulário fora do DOM ou anexá-lo ao corpo, se desejar, e mover o elemento de entrada para dentro desse formulário. Em seguida, você redefiniria o novo formulário, moveria o elemento de entrada de volta para onde estava e removeria o elemento de formulário adicional.
precisa saber é o seguinte

4
Acabei de descobrir que isso não funciona no IE 11. Estamos usando o PixelFileInput - que usa essa abordagem. E enquanto o texto e a miniatura são limpos, a lista de arquivos do objeto permanece a mesma :(
Ian Grainger

434

Resposta rápida: substitua-o.

No código abaixo, eu uso o replaceWithmétodo jQuery para substituir o controle por um clone próprio. Caso você tenha algum manipulador vinculado a eventos nesse controle, queremos preservá-lo também. Para fazer isso, passamos truecomo o primeiro parâmetro do clonemétodo.

<input type="file" id="control"/>
<button id="clear">Clear</button>
var control = $("#control");

$("#clear").on("click", function () {
    control.replaceWith( control = control.clone( true ) );
});

Fiddle: http://jsfiddle.net/jonathansampson/dAQVM/

Se a clonagem, enquanto preserva os manipuladores de eventos, apresenta qualquer problema que você possa considerar ao usar a delegação de eventos para manipular cliques neste controle a partir de um elemento pai:

$("form").on("focus", "#control", doStuff);

Isso evita a necessidade de qualquer manipulador ser clonado junto com o elemento quando o controle está sendo atualizado.


50
Você também pode usar o método .clone () no campo $ ('# clone'). ReplaceWith ($ (this) .clone ());
#

4
Ele simplesmente não faz nada - nenhum erro no firebug. Eu tive que adicionar control.val (''); para limpar a caixa de entrada do arquivo. Seu código funcionou no chrome e ie9 como está.
MNSR

10
Ainda não funciona. Ele precisa ser limpo antes da substituição. Então você deseja .val () antes de .replaceWith (). Portanto, seria control.val (''). ReplaceWith (...);
MNSR

6
Eu tenho uma solução abaixo que é muito mais limpo do que isso: stackoverflow.com/a/13351234/909944
slipheed

2
esta resposta está aqui por razões históricas. suporte a navegadores modernosinput.value = null;
André Werlang

113

O Jquery deve cuidar dos problemas entre navegadores / navegadores antigos para você.

Isso funciona em navegadores modernos que eu testei: Chromium v25, Firefox v20, Opera v12.14

Usando jquery 1.9.1

HTML

<input id="fileopen" type="file" value="" />
<button id="clear">Clear</button>

Jquery

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

Em jsfiddle

A seguinte solução javascript também funcionou para mim nos navegadores mencionados acima.

document.getElementById("clear").addEventListener("click", function () {
    document.getElementById("fileopen").value = "";
}, false);

Em jsfiddle

Não tenho como testar com o IE, mas teoricamente isso deve funcionar. Se o IE for diferente o suficiente para que a versão Javascript não funcione porque a MS o fez de uma maneira diferente, na minha opinião, o método jquery deve lidar com isso para você; caso contrário, vale a pena apontar para a equipe jquery junto com o método que o IE exige. (Vejo pessoas dizendo "isso não funcionará no IE", mas nenhum javascript de baunilha para mostrar como ele funciona no IE (supostamente um "recurso de segurança"?), Talvez relate isso como um bug para a MS também (se eles conte-o como tal), para que seja corrigido em qualquer versão mais recente)

Como mencionado em outra resposta, uma postagem no fórum jquery

 if ($.browser.msie) {
      $('#file').replaceWith($('#file').clone());
 } else {
      $('#file').val('');
 }

Mas o jquery agora removeu o suporte para testes de navegador, jquery.browser.

Essa solução javascript também funcionou para mim, é o equivalente baunilha do método jquery.replaceWith .

document.getElementById("clear").addEventListener("click", function () {
    var fileopen = document.getElementById("fileopen"),
        clone = fileopen.cloneNode(true);

    fileopen.parentNode.replaceChild(clone, fileopen);
}, false);

Em jsfiddle

O importante a ser observado é que o cloneNode método não preserva os manipuladores de eventos associados.

Veja este exemplo.

document.getElementById("fileopen").addEventListener("change", function () {
    alert("change");
}, false);

document.getElementById("clear").addEventListener("click", function () {
    var fileopen = document.getElementById("fileopen"),
        clone = fileopen.cloneNode(true);

    fileopen.parentNode.replaceChild(clone, fileopen);
}, false);

Em jsfiddle

Mas o jquery.clone oferece isso [* 1]

$("#fileopen").change(function () {
    alert("change");
});

$("#clear").click(function () {
    var fileopen = $("#fileopen"),
        clone = fileopen.clone(true);

    fileopen.replaceWith(clone);
});

Em jsfiddle

[* 1] O jquery é capaz de fazer isso se os eventos foram adicionados pelos métodos do jquery, pois mantém uma cópia em jquery.data ; ele não funciona de outra forma; portanto, é um truque / solução alternativa e significa que as coisas não são compatível entre diferentes métodos ou bibliotecas.

document.getElementById("fileopen").addEventListener("change", function () {
    alert("change");
}, false);

$("#clear").click(function () {
    var fileopen = $("#fileopen"),
        clone = fileopen.clone(true);

    fileopen.replaceWith(clone);
});

Em jsfiddle

Você não pode obter o manipulador de eventos anexado diretamente do próprio elemento.

Aqui está o princípio geral no vanilla javascript, é assim que o jquery e todas as outras bibliotecas o fazem (aproximadamente).

(function () {
    var listeners = [];

    function getListeners(node) {
        var length = listeners.length,
            i = 0,
            result = [],
            listener;

        while (i < length) {
            listener = listeners[i];
            if (listener.node === node) {
                result.push(listener);
            }

            i += 1;
        }

        return result;
    }

    function addEventListener(node, type, handler) {
        listeners.push({
            "node": node,
                "type": type,
                "handler": handler
        });

        node.addEventListener(type, handler, false);
    }

    function cloneNode(node, deep, withEvents) {
        var clone = node.cloneNode(deep),
            attached,
            length,
            evt,
            i = 0;

        if (withEvents) {
            attached = getListeners(node);
            if (attached) {
                length = attached.length;
                while (i < length) {
                    evt = attached[i];
                    addEventListener(clone, evt.type, evt.handler);

                    i += 1;
                }
            }
        }

        return clone;
    }

    addEventListener(document.getElementById("fileopen"), "change", function () {
        alert("change");
    });

    addEventListener(document.getElementById("clear"), "click", function () {
        var fileopen = document.getElementById("fileopen"),
            clone = cloneNode(fileopen, true, true);

        fileopen.parentNode.replaceChild(clone, fileopen);
    });
}());

Em jsfiddle

É claro que o jquery e outras bibliotecas têm todos os outros métodos de suporte necessários para manter essa lista; isso é apenas uma demonstração.


Isso funciona! (bem, pelo menos, o bit baunilha JS no início desta resposta). Eu testei isso no mais recente Chrome, Firefox e IE (11).
PhilT

4
Eu estava prestes a adicionar algumas das suas mesmas respostas, mas principalmente isso .val(''). Não é apenas mais simples do que clonar o elemento de upload ou adicionar um formulário aninhado? +1.
Erenor Paz

3
A primeira solução JQuery (usando .val("")) funcionou perfeitamente, obrigado. Muito mais simples do que clonar a entrada e substituí-la também.
Hugo Zink

51

Por razões óbvias de segurança, você não pode definir o valor de uma entrada de arquivo, nem mesmo para uma sequência vazia.

Tudo o que você precisa fazer é redefinir o formulário em que o campo ou se você deseja redefinir apenas a entrada de arquivo de um formulário contendo outros campos, use o seguinte:

function reset_field (e) {
    e.wrap('<form>').parent('form').trigger('reset');
    e.unwrap();
}​

Aqui está um exemplo: http://jsfiddle.net/v2SZJ/1/


6
Não funciona corretamente no IE. O valor visual é redefinido, mas o el.value ainda relata a versão anterior. Ajuda a redefinir o el.value, mas apenas no IE10 +.jsfiddle.net/9uPh5/2
Gregor

2
A mesma solução acima
PhilT 22/04/2015

2
Isso está errado, não podemos definir o campo para um determinado valor, mas espero que possamos limpá-lo.
Fralbo 22/09/2015


20

No IE8, eles fizeram o campo Upload de arquivos somente leitura por segurança. Veja a postagem no blog da equipe do IE :

Historicamente, o HTML File Upload Control () tem sido a fonte de um número significativo de vulnerabilidades de divulgação de informações. Para resolver esses problemas, duas alterações foram feitas no comportamento do controle.

Para bloquear ataques que dependem de "roubar" pressionamentos de tecla para induzir clandestinamente o usuário a digitar um caminho de arquivo local no controle, a caixa de edição Caminho do arquivo agora é somente leitura. O usuário deve selecionar explicitamente um arquivo para upload usando a caixa de diálogo Procurar arquivo.

Além disso, o URLAction “Incluir caminho do diretório local ao fazer upload de arquivos” foi definido como "Desativar" para a Zona da Internet. Essa alteração evita o vazamento de informações do sistema de arquivos local potencialmente confidenciais para a Internet. Por exemplo, em vez de enviar o caminho completo C: \ users \ ericlaw \ documents \ secret \ image.png, o Internet Explorer 8 agora enviará apenas o nome do arquivo image.png.


16

$("#control").val('')é tudo o que você precisa! Testado no Chrome usando o JQuery 1.11

Outros usuários também testaram no Firefox.


2
Como muitos outros posts aqui explicam, isso não é compatível com vários navegadores.
Tisch

Para meu entendimento, em quais navegadores isso falha?
TheHamstring

1
Falha no Internet Explorer, pois o arquivo do tipo de entrada é somente leitura no IE>
Lucky

4
Funciona em chrome e firefox. Mais que o suficiente.
precisa saber é o seguinte

12

Fiquei preso com todas as opções aqui. Aqui está um truque que eu fiz que funcionou:

<form>
 <input type="file">
 <button type="reset" id="file_reset" style="display:none">
</form>

e você pode acionar a redefinição usando jQuery com um código semelhante a este:

$('#file_reset').trigger('click');

(jsfiddle: http://jsfiddle.net/eCbd6/ )


3
ok, mas ele irá limpar o formulário inteiro .. entrada de arquivo não específica
Ashish Ratan

8

Eu acabei com isso:

if($.browser.msie || $.browser.webkit){
  // doesn't work with opera and FF
  $(this).after($(this).clone(true)).remove();  
}else{
  this.setAttribute('type', 'text');
  this.setAttribute('type', 'file'); 
}

pode não ser a solução mais elegante, mas funciona até onde eu sei.



não funciona no chrome 34 (linux). replaceWith () método funciona em ambos os navegadores (Chrome, Firefox)
Gaurav Sharma

No começo, devo observar "O navegador $ foi removido do jquery 1.9", mas as duas últimas linhas (Alterando o atributo type para texto e depois devolvendo-o ao arquivo) funcionaram. Além disso, tentei definir $ ('# control'). Val (''); ou no javascript document.getElementById (control) .value = ''; e funcionou também e não sabe por que não devemos usar essa abordagem !? Finalmente, eu decidi usar os dois.
QMaster 7/10

8

Eu usei https://github.com/malsup/form/blob/master/jquery.form.js , que tem uma função chamadaclearInputs() , que é cross-browser, bem testada, fácil de usar e também lida com problemas do IE e limpeza de campos ocultos se necessário. Talvez seja uma solução um pouco longa para limpar apenas a entrada de arquivos, mas se você estiver lidando com uploads de arquivos entre navegadores, essa solução é recomendada.

O uso é fácil:

// Limpe todos os campos do arquivo:
$ ("input: file"). clearInputs ();

// Limpe também os campos ocultos:
$ ("input: file"). clearInputs (true);

// Limpe campos específicos:
$ ("# myfilefield1, # ​​myfilefield2"). clearInputs ();
/ **
 * Limpa os elementos de formulário selecionados.
 * /
$ .fn.clearFields = $ .fn.clearInputs = função (includeHidden) {
    var re = / ^ (?: cor | data | datetime | email | mês | número | senha | intervalo | pesquisa | tel | texto | tempo | url | semana) $ / i; // 'hidden' não está nesta lista
    retorne this.each (function () {
        var t = this.type, tag = this.tagName.toLowerCase ();
        if (re.test (t) || tag == 'textarea') {
            this.value = '';
        }
        caso contrário, se (t == 'caixa de seleção' || t == 'rádio') {
            this.checked = false;
        }
        caso contrário, se (tag == 'selecionar') {
            this.selectedIndex = -1;
        }
        caso contrário, se (t == "arquivo") {
            if (/MSIE/.test(navigator.userAgent)) {
                $ (this) .replaceWith ($ (this) .clone (true));
            } outro {
                $ (this) .val ('');
            }
        }
        caso contrário, se (includeHidden) {
            // includeHidden pode ser o valor true ou uma sequência de seleção
            // indicando um teste especial; por exemplo:
            // $ ('# myForm'). clearForm ('. special: hidden')
            // o acima limparia entradas ocultas que têm a classe 'especial'
            if ((includeHidden === true && /hidden/.test(t)) ||
                 (typeof includeHidden == 'string' && $ (this) .is (includeHidden)))
                this.value = '';
        }
    });
};

Não entendo por que essa resposta não é mais votada ?!
AlexB

1
@AlexB: Porque, como Timo explicou, é um exagero apenas limpar um campo de entrada de arquivo.
TheCarver 14/02

Não sei se isso funcionou, mas não mais no FF 45.0.2 :(
fralbo 5/05

5

O valor das entradas do arquivo é somente leitura (por razões de segurança). Você não pode colocá-lo em branco programaticamente (exceto chamando o método reset () do formulário, que tem um escopo mais amplo do que apenas esse campo).


16
Estou confuso - tentei $ ("# inputControl"). Val ("") e de fato deixou o campo em branco. Estou esquecendo de algo?
Sampson

1
@ Jonathan, funciona para mim também, mas se você configurá-lo para qualquer outra coisa, é um erro de segurança. Testado em FF4.
Brenden

reset () é um método nativo JS; portanto, se você selecionar o formulário via jQuery, precisará retirar o elemento do escopo do jQuery. $ ("form # myForm") [0] .reset ();
Chris Stephens

4
@ Jonathan Ele funciona para você porque você não fez no IE. Esse problema de segurança é algo que apenas o IE para. Limpando o valor trabalha regularmente em ambos Chrome e Firefox, mas não IE
VoidKing

5

Consegui fazer o meu trabalhar com o seguinte código:

var input = $("#control");    
input.replaceWith(input.val('').clone(true));

5

Eu tenho procurado uma maneira simples e limpa de limpar a entrada de arquivos HTML, as respostas acima são ótimas, mas nenhuma delas realmente responde ao que estou procurando, até que me deparei com a Web com uma maneira simples e elegante de fazer isso:

var $input = $("#control");

$input.replaceWith($input.val('').clone(true));

todo o crédito é para Chris Coyier .

// Referneces
var control = $("#control"),
    clearBn = $("#clear");

// Setup the clear functionality
clearBn.on("click", function(){
    control.replaceWith( control.val('').clone( true ) );
});

// Some bound handlers to preserve when cloning
control.on({
    change: function(){ console.log( "Changed" ) },
     focus: function(){ console.log(  "Focus"  ) }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<input type="file" id="control">
<br><br>
<a href="#" id="clear">Clear</a>


4

A .clone()coisa não funciona no Opera (e possivelmente em outros). Mantém o conteúdo.

O método mais próximo aqui para mim foi o de Jonathan, no entanto, garantindo que o campo preservasse seu nome, classes, etc., gerando um código confuso no meu caso.

Algo assim pode funcionar bem (graças a Quentin também):

function clearInput($source) {
    var $form = $('<form>')
    var $targ = $source.clone().appendTo($form)
    $form[0].reset()
    $source.replaceWith($targ)
}

Isso foi testado em todos os principais navegadores?
Shawn

Parece funcionar bem na versão mais recente do Chrome / FF / Opera e no IE8. Não vejo nenhum motivo para não funcionar em nada - a opção de redefinição de formulários já existe há muito tempo.
SpoonNZ

4

Eu consegui fazer isso funcionar usando o seguinte ...

function resetFileElement(ele) 
{
    ele.val(''); 
    ele.wrap('<form>').parent('form').trigger('reset');   
    ele.unwrap();
    ele.prop('files')[0] = null;
    ele.replaceWith(ele.clone());    
}

Isso foi testado no IE10, FF, Chrome e Opera.

Existem duas advertências ...

  1. Ainda não funciona corretamente no FF, se você atualizar a página, o elemento file será preenchido novamente com o arquivo selecionado. De onde está obtendo essa informação está além de mim. O que mais relacionado a um elemento de entrada de arquivo eu poderia tentar limpar?

  2. Lembre-se de usar a delegação em todos os eventos anexados ao elemento de entrada do arquivo, para que eles ainda funcionem quando o clone for criado.

O que não entendo é que quem pensou que não permitir que você limpe um campo de entrada de uma seleção de arquivo inaceitável inválida era uma boa idéia?

OK, não me permita defini-lo dinamicamente com um valor para não poder lixivar arquivos do sistema operacional de um usuário, mas deixe-me limpar uma seleção inválida sem redefinir um formulário inteiro.

Não é como 'aceitar' faz nada além de um filtro e, no IE10, ele nem entende os tipos de mímica do MS Word, é uma piada!


Isso quase funciona. A única coisa que você precisa fazer para que isso funcione no Firefox é usar .pop()a matriz de arquivos em vez de defini-la como nula. isso parece limpar o arquivo corretamente.
22415 kmacdonald

2

No meu Firefox 40.0.3, apenas trabalho com este

 $('input[type=file]').val('');
 $('input[type=file]').replaceWith($('input[type=file]').clone(true));

1
$ ('input [type = file]'). replaceWith ($ ('input [type = file]'). clone (true) .val (''));
Andrei

2

funciona para mim em todos os navegadores.

        var input = $(this);
        var next = this.nextSibling;
        var parent = input.parent();
        var form = $("<form></form>");
        form.append(input);
        form[0].reset();
        if (next) {
            $(next).before(input);
        } else {
            parent.append(input);
        }

1

Tentei com a maioria das técnicas mencionadas pelos usuários, mas nenhuma delas funcionou em todos os navegadores. ou seja: clone () não funciona no FF para entradas de arquivo. Acabei copiando manualmente a entrada do arquivo e substituindo o original pela copiada. Funciona em todos os navegadores.

<input type="file" id="fileID" class="aClass" name="aName"/>

var $fileInput=$("#fileID");
var $fileCopy=$("<input type='file' class='"+$fileInput.attr("class")+" id='fileID' name='"+$fileInput.attr("name")+"'/>");
$fileInput.replaceWith($fileCopy);

0

$("input[type=file]").wrap("<div id='fileWrapper'/>");
$("#fileWrapper").append("<div id='duplicateFile'   style='display:none'>"+$("#fileWrapper").html()+"</div>");
$("#fileWrapper").html($("#duplicateFile").html());

1
Oi Niraj. Bem-vinda. Essa resposta pode estar correta, mas pode ser útil.
tomfanning

0

Isso funciona com Chrome, FF e Safari

$("#control").val("")

Pode não funcionar com o IE ou Opera


1
Parece quase idêntico ao próprio problema no OP
Trindaz 20/12/12

1
não é um padrão de ecmascript, o valor do arquivo do tipo de entrada é uma propriedade de proteção por motivos de segurança.
e-info128

0

Torne-o assíncrono e redefina-o depois que as ações desejadas do botão forem executadas.

    <!-- Html Markup --->
    <input id="btn" type="file" value="Button" onchange="function()" />

    <script>
    //Function
    function function(e) {

        //input your coding here           

        //Reset
        var controlInput = $("#btn");
        controlInput.replaceWith(controlInput = controlInput.val('').clone(true));
    } 
    </script>

0
function clear() {
    var input = document.createElement("input");
    input.setAttribute('type', 'file');
    input.setAttribute('value', '');
    input.setAttribute('id', 'email_attach');

    $('#email_attach').replaceWith( input.cloneNode() );
}

0

Isto não funciona para mim:

$('#Attachment').replaceWith($(this).clone());
or 
$('#Attachment').replaceWith($('#Attachment').clone());

assim, no asp mvc, uso recursos de barbear para substituir a entrada de arquivo. primeiro, crie uma variável para a string de entrada com Id e Nome e, em seguida, use-a para mostrar na página e substituir no botão de redefinição, clique em:

@{
    var attachmentInput = Html.TextBoxFor(c => c.Attachment, new { type = "file" });
}

@attachmentInput

<button type="button" onclick="$('#@(Html.IdFor(p => p.Attachment))').replaceWith('@(attachmentInput)');">--</button>

0

Uma maneira fácil é alterar o tipo de entrada e alterá-lo novamente.

Algo assim:

var input = $('#attachments');
input.prop('type', 'text');
input.prop('type', 'file')

-1

Você pode substituí-lo com o seu clone assim

var clone = $('#control').clone();

$('#control').replacewith(clone);

Mas isso clona com seu valor também, então é melhor você

var emtyValue = $('#control').val('');
var clone = emptyValue.clone();

$('#control').replacewith(clone);

-4

É fácil lol (funciona em todos os navegadores [exceto ópera]):

$('input[type=file]').each(function(){
    $(this).after($(this).clone(true)).remove();
});

JS Fiddle: http://jsfiddle.net/cw84x/1/


Eu não me importo menos com ópera. Basta envolvê-lo no formulário, se você se importa. Pessoalmente, não me importo e usarei meu método.
Anónimo

2
Esta não é uma boa resposta, mas o principal problema foi a péssima atitude #
P Sam P

-5

O que? Na sua função de validação, basta colocar

document.onlyform.upload.value="";

Supondo que upload seja o nome:

<input type="file" name="upload" id="csv_doc"/>

Estou usando JSP, não tenho certeza se isso faz diferença ...

Funciona para mim e acho que é muito mais fácil.

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.