En JavaScript, ¿puedo hacer que un evento "clic" se active mediante programación para un elemento de entrada de archivo?

261

Me gustaría hacer que un evento de clic se active en una <input type="file">etiqueta mediante programación.

Simplemente llamar a click () no parece hacer nada o al menos no aparece un cuadro de diálogo de selección de archivo.

He estado experimentando con la captura de eventos usando oyentes y redirigiendo el evento, pero no he podido lograr que se realice el evento como si alguien hubiera hecho clic en él.

usuario28655
fuente
1
El evento de clic que activa debe llamarse dentro de un evento de clic iniciado por el usuario, o no funcionará.
Umagon

Respuestas:

79

No se puede hacer eso en todos los navegadores, supuestamente IE lo permite, pero Mozilla y Opera no.

Cuando redacta un mensaje en GMail, la función 'adjuntar archivos' se implementa de una manera para IE y cualquier navegador que lo admita, y luego se implementa de otra manera para Firefox y aquellos navegadores que no lo hacen.

No sé por qué no puede hacerlo, pero una cosa que es un riesgo para la seguridad y que no está permitido hacer en ningún navegador es establecer mediante programación el nombre del archivo en el elemento Archivo HTML.

Jason Bunting
fuente
1
Drat Bueno, ciertamente entiendo que es explotable. ¿Está esto documentado en alguna parte? ¿Supongo que sería implementado por cada navegador?
usuario28655
Actualicé mi respuesta para que sea más correcta que la respuesta anterior: la esencia es la misma, pero la aclaración debería ayudar un poco. Este tipo se encontró con el mismo problema: bytes.com/forum/thread542877.html
Jason Bunting
Gracias Dios FF5 permite este clic
rshimoda
2
Para aclarar el comentario anterior: Chrome cambió recientemente para verificar si el inputelemento del archivo está visible. Activar el clickmétodo funciona, incluso en la consola, si se puede ver el elemento.
jwadsack
2
@Otvazhnii - amigo, esta respuesta (la que estás diciendo que está mal) tiene 10 años, ¡no es de extrañar que no sea correcta! (No estoy seguro, estoy tomando tu palabra). : P
Jason Bunting
257

He estado buscando una solución para todo este día. Y estas son las conclusiones que he hecho:

  1. Por razones de seguridad, Opera y Firefox no permiten activar la entrada de archivos.
  2. La única alternativa conveniente es crear una entrada de archivo "oculta" (usando opacidad, no "oculta" o "mostrar: ninguna") y luego crear el botón "debajo". De esta forma se ve el botón, pero al hacer clic en el usuario, se activa la entrada del archivo.

¡Espero que esto ayude! :)

<div style="display: block; width: 100px; height: 20px; overflow: hidden;">
<button style="width: 110px; height: 30px; position: relative; top: -5px; left: -5px;"><a href="javascript: void(0)">Upload File</a></button>
<input type="file" id="upload_input" name="upload" style="font-size: 50px; width: 120px; opacity: 0; filter:alpha(opacity=0);  position: relative; top: -40px;; left: -20px" />
</div>
Romas
fuente
66
Esta solución funciona muy bien. No estoy seguro de por qué se ha pasado por alto y no ha sido actualizado. No es * exactamente lo que pide la pregunta, pero es una gran solución. ¿Le ha resultado incompatible con algún navegador? No tengo tiempo para abrirme camino a través de los más de 10 sabores de los relevantes para probar.
Yevgeny Simkin
1
Gracias por esta respuesta, es increíble: D
mario.tco
Buena solución Funciona en el navegador móvil Android también.
gstroup
1
Esto no es cierto, ver la respuesta de Didier a continuación. El clic programático debe provenir del contexto de acción del usuario, como en el controlador de clic de otro botón. Entonces funciona bien, no es necesario tener un elemento de desbordamiento.
smok
1
El único problema con esto es que si desea cambiar el estilo del botón al pasar el mouse, no puede. Lo que significa que si quieres que se vea como todos los demás botones de tu aplicación, no puedes.
Vincent
68

Puede disparar click () en cualquier navegador, pero algunos navegadores necesitan que el elemento esté visible y enfocado. Aquí hay un ejemplo de jQuery:

$('#input_element').show();
$('#input_element').focus();
$('#input_element').click();
$('#input_element').hide();

Funciona con el hide antes del, click()pero no sé si funciona sin llamar al método show. Nunca probé esto en Opera, lo probé en IE / FF / Safari / Chrome y funciona. Espero que esto sea de ayuda.

Florin Mogos
fuente
51
Gracias por compartir. En caso de que no lo supieras, puedes usar el encadenamiento en jQuery: $(...).show().focus().click().hide();:)
pimvdb
1
@pimvdb: por lo que pruebo, su solución solo funciona en Chrome.
Hoàng Long
1
@ Hoàng Long: ¿Te refieres al encadenamiento o la solución de Florin Mogos? No creo que el encadenamiento haga ninguna diferencia entre navegadores.
pimvdb
1
@ HoàngLong Funciona para mí en IE 8 y 9, las últimas Chrome, Safari y Firefox.
Sami Samhuri
2
Extraño. Como probé, no funciona bajo Chrome en Ubuntu.
sandrew
29

ESTO ES POSIBLE: Bajo FF4 +, Opera?, Chrome: pero:

  1. inputElement.click()debe llamarse desde el contexto de acción del usuario! (no contexto de ejecución de script)

  2. <input type="file" />debe ser visible ( inputElement.style.display !== 'none') (puede ocultarlo con visibilidad u otra cosa, pero no con la propiedad "mostrar")

Didier Ghys
fuente
Esto lo resolvió para mí. Tuve que agregar el javascript al onclickatributo en lugar de vincularlo al evento.
jasonlfunk
1
Votar la única solución razonable. El método de desbordamiento es feo.
smok
¡Decir ah! ¡Sabía que tenía que ser algo relacionado con el contexto! Había observado que las llamadas inputElement.click()desde un evento keydown (acceso directo para adjuntar un archivo) funcionaban, pero no lo hacía en un tiempo de espera o devolución de llamada ajax. Votado
brettjonesdev
9
Por cierto, ¿alguien tiene más recursos sobre el "contexto de acción del usuario" frente al "contexto de ejecución de script"? Todo lo que veo cuando busco tiene que ver con el contexto de ejecución y this. : /
brettjonesdev
@bretjonesdev Creo que eso significa que debe ejecutarse dentro de un controlador de eventos iniciado por el usuario, como un controlador de eventos de clic, en lugar de una promesa, tiempo de espera o cualquier otro evento no iniciado por el usuario.
Alex Guerra
10

Para aquellos que entienden que tienes que superponer una forma invisible sobre el enlace, pero son demasiado flojos para escribir, lo escribí para ti. Bueno, para mí, pero bien podría compartir. Comentarios son bienvenidos

HTML (en alguna parte):

<a id="fileLink" href="javascript:fileBrowse();" onmouseover="fileMove();">File Browse</a>

HTML (en algún lugar que no te interese):

<div id="uploadForm" style="filter:alpha(opacity=0); opacity: 0.0; width: 300px; cursor: pointer;">
    <form method="POST" enctype="multipart/form-data">
        <input type="file" name="file" />
    </form>
</div>

JavaScript:

function pageY(el) {
    var ot = 0;
    while (el && el.offsetParent != el) {
        ot += el.offsetTop ? el.offsetTop : 0;
        el = el.offsetParent;
    }
    return ot;
}

function pageX(el) {
    var ol = 0;
    while (el && el.offsetParent != el) {
        ol += el.offsetLeft ? el.offsetLeft : 0;
        el = el.offsetParent;
    }
    return ol;
}

function fileMove() {
    if (navigator.appName == "Microsoft Internet Explorer") {
        return; // Don't need to do this in IE. 
    }
    var link = document.getElementById("fileLink");
    var form = document.getElementById("uploadForm");
    var x = pageX(link);
    var y = pageY(link);
    form.style.position = 'absolute';
    form.style.left = x + 'px';
    form.style.top = y + 'px';
}

function fileBrowse() {
    // This works in IE only. Doesn't do jack in FF. :( 
    var browseField = document.getElementById("uploadForm").file;
    browseField.click();
}
McTrafik
fuente
7

Si desea que el clickmétodo funcione en Chrome, Firefox, etc., aplique el siguiente estilo a su archivo de entrada. Estará perfectamente oculto, es como si hicieras undisplay: none;

#fileInput {
    visibility: hidden;
    position: absolute;
    top: 0;
    left: -5000px;
}

Es así de simple, ¡probé que funciona!

Linblow
fuente
Me gusta de esta manera, ya que algunos navegadores antiguos no harán nada en inputElement.click () si está oculto.
Nick
¿Por qué no simplemente configurar el heighty widthpara 0?
Solomon Ucko
5
$(document).one('mousemove', function() { $(element).trigger('click') } );

Me funcionó cuando me encontré con un problema similar, es un eRube Goldberg normal.

Leon Creatini
fuente
4

SOLUCIÓN DE TRABAJO

Permítanme agregar a esta publicación anterior, una solución de trabajo que solía usar que funciona en probablemente el 80% o más de todos los navegadores tanto nuevos como antiguos.

La solución es compleja pero simple. El primer paso es hacer uso de CSS y disimular el tipo de archivo de entrada con "subelementos" que se muestran ya que tiene una opacidad de 0. El siguiente paso es usar JavaScript para actualizar su etiqueta según sea necesario.

HTML Los ID simplemente se insertan si desea una forma rápida de acceder a un elemento específico, sin embargo, las clases son imprescindibles ya que se relacionan con el CSS que configura todo este proceso

<div class="file-input wrapper">
    <input id="inpFile0" type="file" class="file-input control" />
    <div class="file-input content">
        <label id="inpFileOutput0" for="inpFileButton" class="file-input output">Click Here</label>
        <input id="inpFileButton0" type="button" class="file-input button" value="Select File" />
    </div>
</div>

CSS Tenga en cuenta que los colores y los estilos de fuente son su preferencia, si usa este CSS básico, siempre puede usar el marcado posterior al estilo que desee, esto se muestra en el jsFiddle que se encuentra al final.

.file-test-area {
    border: 1px solid;
    margin: .5em;
    padding: 1em;
}
.file-input {
    cursor: pointer !important;
}
.file-input * {
    cursor: pointer !important;
    display: inline-block;
}
.file-input.wrapper {
    display: inline-block;
    font-size: 14px;
    height: auto;
    overflow: hidden;
    position: relative;
    width: auto;
}
.file-input.control {
    -moz-opacity:0 ;
    filter:alpha(opacity: 0);
    opacity: 0;

    height: 100%;
    position: absolute;
    text-align: right;
    width: 100%;
    z-index: 2;
}
.file-input.content {
    position: relative;
    top: 0px;
    left: 0px;
    z-index: 1;
}
.file-input.output {
    background-color: #FFC;
    font-size: .8em;
    padding: .2em .2em .2em .4em;
    text-align: center;
    width: 10em;
}
.file-input.button {
    border: none;
    font-weight: bold;
    margin-left: .25em;
    padding: 0 .25em;
}

JavaScript puro y verdadero, sin embargo, algunos navegadores ANTERIORES (retirados) aún pueden tener problemas con él (¡como Netscrape 2!)

var inp = document.getElementsByTagName('input');
for (var i=0;i<inp.length;i++) {
    if (inp[i].type != 'file') continue;
    inp[i].relatedElement = inp[i].parentNode.getElementsByTagName('label')[0];
    inp[i].onchange /*= inp[i].onmouseout*/ = function () {
        this.relatedElement.innerHTML = this.value;
    };
};

Ejemplo de trabajo de jsFiddle

SpYk3HH
fuente
4

Funciona :

Por razones de seguridad en Firefox y Opera, no puede activar el clic en la entrada del archivo, pero puede simular con MouseEvents:

<script>
click=function(element){
    if(element!=null){
        try {element.click();}
        catch(e) {
            var evt = document.createEvent("MouseEvents");
            evt.initMouseEvent("click",true,true,window,0,0,0,0,0,false,false,false,false,0,null);
            element.dispatchEvent(evt);
            }
        }
    };
</script>

<input type="button" value="upload" onclick="click(document.getElementById('inputFile'));"><input type="file" id="inputFile" style="display:none">
kop
fuente
1
Tenga en cuenta que createEvent()y initMouseEvent()ahora están en desuso.
Alexis Wilke
4

Sé que esto es antiguo, y todas estas soluciones son trucos en torno a las precauciones de seguridad del navegador con un valor real.

Dicho esto, a partir de hoy, fileInput.click () funciona en Chrome actual (36.0.1985.125 m) y Firefox ESR actual (24.7.0), pero no en IE actual (11.0.9600.17207). La superposición de un campo de archivo con opacidad 0 en la parte superior de un botón funciona, pero quería un elemento de enlace como activador visible, y el subrayado de desplazamiento no funciona en ningún navegador. Parpadea y luego desaparece, probablemente el navegador piensa si el estilo de desplazamiento realmente se aplica o no.

Pero encontré una solución que funciona en todos esos navegadores. No afirmaré haber probado todas las versiones de cada navegador, o que sé que seguirá funcionando para siempre, pero parece que ahora satisface mis necesidades.

Es simple: coloque el campo de entrada del archivo fuera de la pantalla (posición: absoluto; arriba: -5000 px), coloque un elemento de etiqueta a su alrededor y active el clic en la etiqueta, en lugar del campo del archivo en sí.

Tenga en cuenta que el enlace debe estar programado para llamar al método de clic de la etiqueta, no lo hace automáticamente, como cuando hace clic en el texto dentro de un elemento de etiqueta. Aparentemente, el elemento de enlace captura el clic y no llega a la etiqueta.

Tenga en cuenta también que esto no proporciona una forma de mostrar el archivo seleccionado actualmente, ya que el campo está fuera de pantalla. Quería enviar de inmediato cuando se seleccionó un archivo, por lo que no es un problema para mí, pero necesitará un enfoque algo diferente si su situación es diferente.

enigmento
fuente
De acuerdo, en la etiqueta del botón, onclick = "filetag.click ()" no funciona con IE 9 y 10 (pero funciona con IE 11, Firefox 4/10/26/27/28, Chrome / Chromium 31/32/33 / 36, Safari 7, Opera 23). Pero, si usa una etiqueta para = "id-of-file-input" (sin onlick), funciona para IE 10/09/11.
luigifab
4

JS Fiddle: http://jsfiddle.net/eyedean/1bw357kw/

popFileSelector = function() {
    var el = document.getElementById("fileElem");
    if (el) {
        el.click();  
    }
};

window.popRightAway = function() {
    document.getElementById('log').innerHTML += 'I am right away!<br />';
    popFileSelector();
};

window.popWithDelay = function() {
    document.getElementById('log').innerHTML += 'I am gonna delay!<br />';
    window.setTimeout(function() {
        document.getElementById('log').innerHTML += 'I was delayed!<br />';
        popFileSelector();
    }, 1000);
};
<body>
  <form>
      <input type="file" id="fileElem" multiple accept="image/*" style="display:none" onchange="handleFiles(this.files)" />
  </form>
  <a onclick="popRightAway()" href="#">Pop Now</a>
    <br />
  <a onclick="popWithDelay()" href="#">Pop With 1 Second Delay</a>
    <div id="log">Log: <br /></div>
</body>

Ayuda en
fuente
3

Este código me funciona. ¿Es esto lo que estas tratando de hacer?

<input type="file" style="position:absolute;left:-999px;" id="fileinput" />
<button  id="addfiles" >Add files</button>

<script language="javascript" type="text/javascript">
   $("#addfiles").click(function(){
      $("#fileinput").click();
   });
</script>
Mat J
fuente
3

Mi solución para Safari con jQuery y jQuery-ui:

$("<input type='file' class='ui-helper-hidden-accessible' />").appendTo("body").focus().trigger('click');
Adiós
fuente
Aviso: no funciona para Firefox 33, Chrome 38. El disparador ('clic') solo puede funcionar dentro del contexto de evento de interacción del usuario - controladores de eventos.
Amit G
3

Aquí hay una solución de JavaScript pura para este problema. Funciona bien en todos los navegadores

<script>
    function upload_image_init(){
        var elem = document.getElementById('file');
        if(elem && document.createEvent) {
           var evt = document.createEvent("MouseEvents");
           evt.initEvent("click", true, false);
           elem.dispatchEvent(evt);
        }
    }
</script>
Adam Fischer
fuente
2

Hay formas de redirigir los eventos al control, pero no espere poder disparar fácilmente los eventos al control de incendios usted mismo, ya que los navegadores intentarán bloquearlo por (buenas) razones de seguridad.

Si solo necesita que se muestre el cuadro de diálogo de archivo cuando un usuario hace clic en algo, digamos que si desea que los botones de carga de archivos se vean mejor, es posible que desee echar un vistazo a lo que se le ocurrió a Shaun Inman .

He podido lograr la activación del teclado con un cambio creativo de enfoque dentro y fuera del control entre los eventos de pulsación de tecla, pulsación de tecla y activación de teclas. YMMV.

Mi sincero consejo es dejar esto solo, porque este es un mundo de dolor de incompatibilidad del navegador. Las actualizaciones menores del navegador también pueden bloquear trucos sin previo aviso y es posible que deba reinventar los hacks para que siga funcionando.

Borgar
fuente
2

Estaba investigando esto hace un tiempo porque quería crear un botón personalizado que abriera el diálogo del archivo e iniciara la carga de inmediato. Acabo de notar algo que podría hacer esto posible: Firefox parece abrir el cuadro de diálogo cuando hace clic en cualquier parte de la carga. Entonces lo siguiente podría hacerlo:

  1. Cree una carga de archivo y un elemento separado que contenga una imagen que desee usar como botón
  2. Organícelos para que se superpongan y haga que el fondo del elemento del archivo y el borde sean transparentes para que el botón sea lo único visible
  3. Agregue el javascript para que IE abra el cuadro de diálogo cuando haga clic en el botón / entrada de archivo
  4. Use un evento onchange para enviar el formulario cuando se selecciona un archivo

Esto es solo teórico ya que ya usé otro método para resolver el problema, pero podría funcionar.

usuario83358
fuente
2

Tenía una <input type="button">etiqueta oculta a la vista. Lo que hice fue adjuntar el"onClick" evento a cualquier componente visible de cualquier tipo, como una etiqueta. Esto se realizó utilizando las Herramientas para desarrolladores de Google Chrome o Firebug de Mozilla Firefox utilizando el comando "editar HTML" con el botón derecho. En este caso, especifique el siguiente script o algo similar:

Si tienes JQuery:

$('#id_of_component').click();

si no:

document.getElementById('id_of_component').click();

Gracias.

Kurt
fuente
2

Hola, esta solución funciona. para descargar deberíamos estar usando MSBLOB

$scope.getSingleInvoicePDF = function(invoiceNumberEntity) {
   var fileName = invoiceNumberEntity + ".pdf";
   var pdfDownload = document.createElement("a");
   document.body.appendChild(pdfDownload);

   AngularWebService.getFileWithSuffix("ezbillpdfget",invoiceNumberEntity,"pdf" ).then(function(returnedJSON) {
       var fileBlob = new Blob([returnedJSON.data], {type: 'application/pdf'});
       if (navigator.appVersion.toString().indexOf('.NET') > 0) { // for IE browser
           window.navigator.msSaveBlob(fileBlob, fileName);
       } else { // for other browsers
           var fileURL = window.URL.createObjectURL(fileBlob);
           pdfDownload.href = fileURL;
           pdfDownload.download = fileName;
           pdfDownload.click();      
       }
   });
};

Para AngularJS o incluso para JavaScript normal.

Shankar Shastri
fuente
1

Esto ahora será posible en Firefox 4, con la advertencia de que cuenta como una ventana emergente y, por lo tanto, se bloqueará siempre que haya sido una ventana emergente.

Neil
fuente
2
En realidad, firefox4 mejora mucho el estado de carga de archivos. Mi problema es cómo hacer lo mismo en el navegador Google Chrome.
erick2red
1

Aquí hay una solución que funciona para mí: CSS:

#uploadtruefield {
    left: 225px;
    opacity: 0;
    position: absolute;
    right: 0;
    top: 266px;
    opacity:0;
    -moz-opacity:0;
    filter:alpha(opacity:0);
    width: 270px;
    z-index: 2;
}

.uploadmask {
    background:url(../img/browse.gif) no-repeat 100% 50%;
}
#uploadmaskfield{
    width:132px;
}

HTML con ayuda "pequeña" de JQuery:

<div class="uploadmask">
    <input id="uploadmaskfield" type="text" name="uploadmaskfield">
</div>
<input id="uploadtruefield"  type="file" onchange="$('#uploadmaskfield').val(this.value)" >

Solo asegúrate de que maskfied esté cubierto completamente por el campo de carga real.

DejanR
fuente
1

Puede hacerlo según la respuesta del cuadro de diálogo Abrir archivo en la etiqueta <a>

<input type="file" id="upload" name="upload" style="visibility: hidden; width: 1px;     height: 1px" multiple />
<a href="" onclick="document.getElementById('upload').click(); return false">Upload</a>
McLosys Creative
fuente
1

Descubrí que si la entrada (archivo) está fuera del formulario, el evento de clic de disparo invoca el diálogo del archivo.

nikita
fuente
1

Espero que esto ayude a alguien: pasé 2 horas golpeándome la cabeza:

En IE8 o IE9, si activa la apertura de una entrada de archivo con javascript de alguna manera (créame, los he probado todos), no le permitirá enviar el formulario usando javascript, simplemente fallará en silencio.

Enviar el formulario a través de un botón de envío regular puede funcionar pero llamando a form.submit (); fallará en silencio.

Tuve que recurrir a la superposición de mi botón de selección de archivo con una entrada de archivo transparente que funciona.

gálatas
fuente
Además, puede envolver la entrada del archivo en una etiqueta para que en IE pueda obtener el área donde se puede hacer clic en la etiqueta para cubrir toda la región del botón, mientras que con solo una etiqueta de entrada de archivo, solo se puede hacer clic en la mitad en IE.
Gálatas
1

Esto funcionó para mí:

<script>
    function sel_file() {
        $("input[name=userfile]").trigger('click');
    }  
</script>

<input type="file" name="userfile" id="userfile" />

<a href="javascript:sel_file();">Click</a>
joan16v
fuente
1

no es imposible:

var evObj = document.createEvent('MouseEvents');
evObj.initMouseEvent('click', true, true, window);  
setTimeout(function(){ document.getElementById('input_field_id').dispatchEvent(evObj); },100);

Pero de alguna manera funciona solo si está en una función que se llamó a través de un evento de clic.

Entonces puede tener la siguiente configuración:

html:

<div onclick="openFileChooser()" class="some_fancy_stuff">Click here to open image chooser</div>
<input type="file" id="input_img">

JavaScript:

    function openFileChooser() {
      var evObj = document.createEvent('MouseEvents');
      evObj.initMouseEvent('click', true, true, window);  
      setTimeout(function()
      { 
        document.getElementById('input_img').dispatchEvent(evObj);      
      },100);      
    }
EscapeNetscape
fuente
Los createEvent()y initMouseEvent()quedaron en desuso. Tienes que usar un CustomEvent()ahora ...
Alexis Wilke
0

Puedes usar

<button id="file">select file</button>
<input type="file" name="file" id="file_input" style="display:none;">
<script>
$('#file').click(function() {
        $('#file_input').focus().trigger('click');
    });
</script>
Avanish Kumar
fuente