Acionar programaticamente a caixa de diálogo “selecionar arquivo”

100

Eu tenho um elemento de entrada de arquivo oculto. É possível acionar sua caixa de diálogo de seleção de arquivo a partir do evento de clique de um botão?

tamakisquare
fonte

Respostas:

146

Se quiser ter seu próprio botão para fazer upload de um arquivo em vez de usar <input type="file" />, você pode fazer algo como:

<input id="myInput" type="file" style="visibility:hidden" />
<input type="button" value="Show Dialog" onclick="$('#myInput').click();" />

Observe que eu usei visibility: hidden, em vez de display: none. Você não pode chamar o evento click em uma entrada de arquivo não exibida.

Mike Gwilt
fonte
Simples para casos básicos, mas não compatível com muitos navegadores. Observe que é uma ideia muito melhor combinar esta solução com a sobreposição do elemento de entrada do arquivo sobre um botão na opacidade: 0, como foi mencionado na resposta do Xeon06.
SquareCat
10
Atualização: em navegadores modernos, você pode clicar em uma entrada que nem mesmo está no DOM. Impressionante!
Adria,
7
Acabei de experimentar click()uma display:noneentrada e funcionou
Daniel Cheung
15
Sim, aqui no ano de 2015, click()em um elemento com display: noneobras! ;) Como as coisas mudaram nos últimos quatro anos.
ffxsam
Em hiddenvez disso, você pode usar o atributo style="visibility:hidden": <input id="myInput" type="file" hidden>( w3schools.com/tags/att_global_hidden.asp )
resposta de
113

A maioria das respostas aqui não contém informações úteis:

Sim, você pode clicar programaticamente no elemento de entrada usando jQuery / JavaScript, mas apenas se fizer isso em um manipulador de eventos pertencente a um evento QUE FOI INICIADO PELO USUÁRIO!

Assim, por exemplo, nada acontecerá se você, o script, clicar programaticamente no botão em um retorno de chamada ajax, mas se você colocar a mesma linha de código em um manipulador de eventos que foi gerado pelo usuário, ele funcionará.

PS A debugger;palavra-chave interrompe a janela de navegação se for anterior ao clique programático ... pelo menos no Chrome 33 ...

Fazi
fonte
como @LouisBataillard corretamente menciona: não apenas o manipulador de eventos original precisa ser iniciado pelo usuário; deve ser especificamente um evento de clique. Aqui está um violino que ele forneceu demonstrando isso: link
Souhaieb Besbes
1
você pode clicar em algo que é gerado dinamicamente. em jquery, isto é$(staticElementParent).on("click", "dynamicChild", function(){})
Daniel Cheung
1
OBRIGADO!!!! Tenho testado todas essas respostas no console javascript e estou ficando louco!
jdkealy
8
Tenho lutado por meia hora para solicitar programaticamente uma janela de entrada de arquivo. NINGUÉM MAIS afirmou que é impossível se o evento não for iniciado pelo usuário ... você merece muito +1.
Umagon
1
A partir do Chrome 62, a debugger;palavra - chave não interrompe mais o clique programático
Chris W.
62

Apenas para registro, existe uma solução alternativa que não requer javascript. É uma espécie de hack, explorando o fato de que clicar em um rótulo define o foco na entrada associada.

Você precisa de um <label>com um foratributo adequado (aponta para a entrada), opcionalmente estilizado como um botão (com bootstrap, use btn btn-default). Quando o usuário clica no rótulo, a caixa de diálogo é aberta, por exemplo:

<!-- optionnal, to add a bit of style -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>

<!-- minimal setup -->
<label for="exampleInput" class="btn btn-default">
  Click me
</label>
<input type="file" id="exampleInput" style="display: none" />

m_x
fonte
2
Eu gosto deste, não quero incluir jQuery completo no meu projeto Angular, funciona bem :)
Starscream1984
1
este comportamento é confiável em todos os navegadores modernos?
JoshuaDavid
Isso funciona sem qualquer tipo de JS, usando comportamento nativo do navegador. Emparelhado com eventos onDrop, a implementação de um upload de arquivo rico em recursos funciona muito bem!
Yanick Rochon
Tive que mexer no CSS, mas funcionou - a saber, a visibilidade de entrada do arquivo com "display: none" não está ok em todos os navegadores. (Mas opacidade de 0, etc, pode ser usada)
driftcatcher
13

Não tenho certeza de como os navegadores lidam com cliques em type="file"elementos (questões de segurança e tudo), mas isso deve funcionar:

$('input[type="file"]').click();

Eu testei este JSFiddle no Chrome, Firefox e Opera e todos eles mostram a caixa de diálogo de navegação de arquivo.

Bojangles
fonte
5
Isso parece funcionar apenas quando o evento de "chamada" é em si um evento de clique. Por exemplo, não parece ser possível abrir a caixa de diálogo do arquivo com base em um hoverevento: jsfiddle.net/UQfaZ/1
Louis B.
Você sabe como isso pode ser testado com Selenium se a entrada não estiver no DOM?
Sebastien Lorber
4

Eu envolvo o input[type=file]em uma tag de rótulo, estilizo de acordo labelcom sua preferência e oculto o input.

<label class="btn btn-default fileLabel" data-toggle="tooltip" data-placement="top" title="Upload">
    <input type="file">
    <span><i class="fa fa-upload"></i></span>
</label>

<style>
    .fileLabel input[type="file"] {
        position: fixed;
        top: -1000px;
    }
</style>

Solução puramente CSS.

Ponyboy
fonte
Basta configurar <input type="file" hidden>para remover a necessidade de aplicar um estilo CSS.
Sylvain Lesage
3

Nativamente, a única maneira é criar um <input type="file">elemento e, em seguida, simular um clique, infelizmente.

Existe um pequeno plugin (plug sem vergonha) que vai tirar a dor de ter que fazer isso o tempo todo: file-dialog

fileDialog()
    .then(file => {
        const data = new FormData()
        data.append('file', file[0])
        data.append('imageName', 'flower')

        // Post to server
        fetch('/uploadImage', {
            method: 'POST',
            body: data
        })
    })
Alister
fonte
3

A melhor solução, funciona em todos os navegadores .. até no celular.

<div class="btn" id="s_photo">Upload</div>

<input type="file" name="s_file" id="s_file" style="opacity: 0;">';

<!--jquery-->

<script>
    $("#s_photo").click(function() {
        $("#s_file").trigger("click");
    });
</script>

Ocultar o tipo de arquivo de entrada causa problemas com os navegadores, a opacidade é a melhor solução porque não está ocultando, apenas não mostrando. :)

Pessa
fonte
1
você deve mencionar que isso requer uma referência jquery.
Brino
A opacidade envolve um conceito totalmente não relacionado - você tem sorte se não afetar seu layout com um elemento "transparente". O elemento deve estar lá, mas não visível, então visibility:hiddendeve ser uma escolha melhor.
conny
visibility: hiddenainda afeta o layout. display: noneé o que você quer.
stommestack
1

Não existe uma maneira cruzada de navegadores de fazer isso, por razões de segurança. O que as pessoas geralmente fazem é sobrepor o arquivo de entrada a qualquer outra coisa e definir sua visibilidade como oculta para que seja acionado por conta própria. Mais informações aqui.

Alex Turpin
fonte
2
O OP está falando <input type="file">, não <select>.
Bojangles
Não é um problema. Já fiz isso antes. Em resposta à sua edição, não é uma maneira de fazê-lo; acionando o evento de clique do elemento com jQuery $.click().
Bojangles
1
@JamWaffles ok, isso é estranho. Lembro-me claramente de passar um dia inteiro nisso há algumas semanas. Não funcionou no Firefox e no IE. Eu me pergunto qual era o negócio ...
Alex Turpin
Curioso. Eu tenho um JSFiddle em minha resposta que funciona com FF. Não consigo testar no IE (estou no Linux), então não sei se ainda vou vomitar.
Bojangles
2
Bom esforço de pesquisa aí! Se eu gastar um centavo para cada vez que os desenvolvedores da web tiverem que transformar algum comportamento normal em algo, eu ficaria podre de rico.
Bojangles
1

Certifique-se de que está usando vinculação para obter adereços de componente em REACT

class FileUploader extends Component {
  constructor (props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
   onChange=(e,props)=>{
    const files = e.target.files;
    const selectedFile = files[0];
    ProcessFileUpload(selectedFile,props.ProgressCallBack,props.ErrorCallBack,props.CompleatedCallBack,props.BaseURL,props.Location,props.FilesAllowed);
  }
   handleClick = () => {
    this.refs.fileUploader.click();
  }
  render()
  {
  return(
      <div>
        <button type="button" onClick={this.handleClick}>Select File</button>  
        <input type='file' onChange={(e)=>this.onChange(e,this.props)} ref="fileUploader" style={{display:"none"}} />
      </div>)
  }
}
m-farhan
fonte
0

Usando jQuery você pode chamar click()para simular um clique.

pdubs
fonte
0

Isso funcionou para mim:

$('#fileInput').val('');
dileepar
fonte
0

Para quem quer o mesmo, mas está usando React

openFileInput = () => {
    this.fileInput.click()
}

<a href="#" onClick={this.openFileInput}>
    <p>Carregue sua foto de perfil</p>
    <img src={img} />
</a>
<input style={{display:'none'}} ref={(input) => { this.fileInput = input; }} type="file"/>
Vinicius lima
fonte
0
<div id="uploadButton">UPLOAD</div>
<form action="[FILE_HANDLER_URL]" style="display:none">
     <input id="myInput" type="file" />
</form>
<script>
  const uploadButton = document.getElementById('uploadButton');
  const myInput = document.getElementById('myInput');

  uploadButton.addEventListener('click', () => {
    myInput.click();
  });
</script>
Yairniz
fonte