Upload de archivos por Ajax con jQuery

  • Por
Script Javascript para realizar un upload de archivos al servidor por Ajax, usando el objeto nativo FormData y con la ayuda de jQuery.

Si nos hubieras preguntado hace años habríamos dicho que era imposible enviar archivos al servidor por Ajax, para hacer un upload sin necesidad de recargar la página. Sin embargo Javascript actualmente sí permite esta posibilidad.

En este artículo vamos a explicar un script Javascript que nos serviría para realizar una conexión por Ajax con un servidor en la que mandemos datos de formulario junto con ficheros de datos. Esa conexión la realizaremos por Ajax, de modo que no se tenga que recargar la página o recurrir a viejos trucos como un iframe.

Para hacer posible este objetivo existe un objeto nativo Javascript llamado FormData que nos permitirá crear la estructura necesaria para enviar datos por post, por medio de programación. Por decirlo de otra manera, con FormData conseguiremos generar lo mismo que hace el navegador automáticamente cuando se realiza el envío de un formulario. Solo que en este caso será mediante Javascript y donde podremos inyectar cualquier dato, incluso aunque no esté presente en un formulario.

Éste sería el único método nativo en Javascript para realizar envío de archivos, para hacer upload a un servidor, por medio de Ajax. Nosotros usamos jQuery para facilitarnos la tarea, pero hay que aclarar especialmente que no es necesario para nada. Es decir, usamos jQuery porque así es más fácil hacer Ajax, siendo más sencillo para los que estamos acostumbrados a esta librería Javascript.

FormData

Merecería la pena tratar aparte FormData, aunque de momento vamos a ofrecer solamente la información necesaria para entender este ejemplo. Es un objeto (quizás se entiende mejor como una clase, aunque sabemos que no existen las clases como tal en Javascript) que nos permite a su vez crear objetos FormData para generar pares clave/valor que luego pueden ser enviados del mismo modo que los formularios. También serán recogidos en el servidor del mismo modo que se reciben los formularios.

Cuando generas un objeto FormData la información que vas agregando con append() usa el formato de los formularios comunes que tienen el atributo "multipart/form-data".

Nota: FormData está presente en todos los navegadores modernos, aunque en el caso de Internet Explorer sólo lo encontraremos a partir de la versión 10.

Cuando tenemos un objeto FormData disponemos en él de un método append() que nos permite agregar ese par llave/valor. Los datos que podemos agregar pueden provenir de formularios que ya tengamos creados, pero también de cualquier otra fuente, recurso o servicio que dispongamos en Javascript. Este método append() recibe varios parámetros, de momento indicaremos como primer parámetro el nombre del dato y como segundo el valor.

var formData = new FormData();
formData.append("clave", "valor");

Mi formulario con campos INPUT FILE

Esta parte es puramente HTML. El formulario lo crearás igual que creas cualquier otro formulario común. Tendrás uno o varios campos FILE que serán los que enviemos por Ajax junto con otros campos que pueda haber.

<form enctype="multipart/form-data" id="formuploadajax" method="post">
        Nombre: <input type="text" name="nombre" placeholder="Escribe tu nombre">
        <br />
        <input  type="file" id="archivo1" name="archivo1"/>
        <br />
        <input  type="file" id="archivo2" name="archivo2"/>
        <br />
        <input type="submit" value="Subir archivos"/>
    </form>
    <div id="mensaje"></div>

Observarás que además del formulario hemos colocado una división con id="mensaje". Luego sobre ese elemento enviaremos el texto de la respuesta de la conexión Ajax. El resto del código es HTML común, donde puedes fijarte que tenemos un campo INPUT TEXT y dos campos INPUT para FILE.

Mi Javascript para realizar el envío de archivos por Ajax

Veremos que realizar un ejemplo de envío por Ajax de archivos es realmente simple, incluso con la propia llamada a Ajax. Lo haremos en pocas líneas de código. No obstante, para aclararnos mejor, explicaremos el código en diversos pasos.

Nota: Queremos justamente mantenerlo sencillo, por eso vamos a resumir los pasos a los mínimos necesarios. Lógicamente con tu Javascript podrás hacer más cosas. Existen scripts en Internet para realizar comportamientos similares pero más complejos, incorporando elementos accesorios como barras de progreso.

Este sería el guión que vamos a tener que implementar:

1) Crear un evento submit para enviar el formulario con jQuery en lugar de dejar que lo envíe por el método predeterminado el navegador.

Este comportamiento es puramente jQuery y si no lo conoces simplemente decirte que está explicado en el Manual de jQuery. Lo consigues con un código como éste.

$("#formuploadajax").on("submit", function(e){
    e.preventDefault();
    var f = $(this);

    // ... resto del código de mi ejercicio
});

2) Generar el objeto FormData a partir del formulario y agregarle los datos del formulario. Además podremos agregar cualquier otro dato, incluso aunque éste no esté en un campo del formulario.

var formData = new FormData(document.getElementById("formuploadajax"));
formData.append("dato", "valor");

Observarás que al hacer el new FormData() enviamos como parámetro el propio formulario, con el objeto formulario nativo de Javascript. Ésto es para que el propio juego de datos se genere a partir de los campos que hay en el HTML del formulario. Con este paso nos ahorramos tener que hacer los append() de cada archivo que queremos subir.

En la segunda línea tenemos una llamada a append() que es innecesaria para cubrir nuestros objetivos, pero que he colocado para que se vea simplemente cómo agregaríamos con ese método cualquier otro dato que podamos necesitar.

3) La llamada a Ajax, que realizamos con el método $.ajax() de jQuery.

Vemos que se deben establecer varias variables de configuración para la conexión Ajax. La que debe llamarte la atención es "data:", que es el juego de datos que queremos enviar por post al servidor. Fíjate que como juego de datos usamos directamente el objeto formData generado anteriormente.

$.ajax({
    url: "recibe.php",
    type: "post",
    dataType: "html",
    data: formData,
    cache: false,
    contentType: false,
    processData: false
})
    .done(function(res){
        $("#mensaje").html("Respuesta: " + res);
    });

También podrás ver como se define un método done() sobre la misma conexión Ajax, para especificar las acciones Javascript a implementar cuando se reciba la respuesta por parte del servidor.

Con eso es todo! no necesitas hacer nada más, al menos por lo que a Javascript respecta, para realizar ese envío de ficheros de manera asíncrona. Ahora te querdaría la parte de gestionar el upload de los archivos del lado del servidor. Eso ya depende del lenguaje de servidor que estés usando. Aquí en DesarrolloWeb.com te lo explicamos en otros artículos para diferentes lenguajes.

Código completo

Para que sea más fácil de ver y por si hay alguna duda, colocamos el código completo de una página que realizaría el upload con Ajax, tal como lo hemos explicado.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Upload de archivos con Ajax</title>
</head>
<body>
    
    <form enctype="multipart/form-data" id="formuploadajax" method="post">
        Nombre: <input type="text" name="nombre" placeholder="Escribe tu nombre">
        <br />
        <input  type="file" id="archivo1" name="archivo1"/>
        <br />
        <input  type="file" id="archivo2" name="archivo2"/>
        <br />
        <input type="submit" value="Subir archivos"/>
    </form>
    <div id="mensaje"></div>
    
    
    <script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
    <script>
    $(function(){
        $("#formuploadajax").on("submit", function(e){
            e.preventDefault();
            var f = $(this);
            var formData = new FormData(document.getElementById("formuploadajax"));
            formData.append("dato", "valor");
            //formData.append(f.attr("name"), $(this)[0].files[0]);
            $.ajax({
                url: "recibe.php",
                type: "post",
                dataType: "html",
                data: formData,
                cache: false,
                contentType: false,
	     processData: false
            })
                .done(function(res){
                    $("#mensaje").html("Respuesta: " + res);
                });
        });
    });
    </script>
</body>
</html>

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir

Comentarios

Jrol

09/2/2015
File Upload
Ejecuté el ejemplo indicado con un fichero test.txt, pero no lo subió al servidor. ¿ Qué pudo pasar ?

Gracias

Luis Ek

04/4/2015
Falto el archivo "recibe.php"
Gracias por la información; sin embargo no esta completo, ya que falto que posteareas el archivo "recibe.php".

saludos!

Leo

16/4/2015
El archivo recibe.php ?
Hola ! el tutorial estaria excelente si suben tambien el recibe.php ! gracias.

Flavia

07/5/2015
Bueno.
Hola, ustedes pueden crear el recibe, la parte más compleja ya está regalada. Lo demás es programación para programadores.

Gracias por el código!!.

Marcos

13/5/2015
Gracias
Hola, muchas gracias por la explicación y el código. Me han caído muy bien en este momento...!

Julio Gonzalez

14/5/2015
Excelente !!!
Gracias Miguel...

Una belleza el codigo, yo estaba utilizando jQuery Form Plugin.
Ya no es necesario..

Saludos...

Daniel

15/5/2015
Excelente
No sean vagos, es más complicado enviar un fichero por Ajax y aqui esta servido en bandeja de plata, el recibe.php lo pueden hacer ustedes

juancarlosun

19/6/2015
Alguna sugerencia al recibe.php??
Saludos,

Algun codigo para el recibe.php?? No se trata de vagancia........

Gracias

Emiliano

02/7/2015
Explicar el recibe.php !
Me sumo al pedido de mostrar como es el codigo del lado del servidor para recibir el archivo. No se trata de vagancia sino de no saber hacerlo.

Jose

23/7/2015
muyyyy bueno
de verdad sencillo y consiso, bueno bueno
se q me va a servir de mucho, yo sabia q ya se podie subir con ajax lo q no me habia hecho falta, ahora encontre este post y se q me va a servir de mucho

Diego

25/8/2015
Consulta
Como puedo pasar una variable desde el form hacia la función en JQuery?

Muchas gracias!

Hector

26/10/2015
Respuesta por parte del servidor
Hola a todos,

lo que hago yo es atacar a un webservice que me genera una respuesta, pero no logro que me la muestre en el cliente. Es más, creo que ni entra al done, porqué he colocado ahí un alert y ni lo lanza.

Alguna idea?

Gracias por el post!

fayensa

03/11/2015
Aclaración llamada Ajax
Para que funcione correctamente el envio de ficheros a traves de ajax es imprescindible pasar los siguientes parámetros a la función:
cache: false,
contentType: false,
processData: false
de otro modo jquery dá un error.

Iván

04/11/2015
Perfecto.. aunque....
Todo lo explicado en este tema esta muy bien y de hecho es comprensible pero no encuentro como recuperar los valores con PHP he intentado de todo pero me muestra que todas mis variables y que intento recuperar no estan inicializadas... a menos que no sepa y es lo mas seguro hacer una recuperacion correcta de los datos. No es que quiera el trabajo hecho pero ya he buscado hasta mas no poder como recuperar esos datos. Si alguien puede orientarme como podria recuperarlos con php partiendo de como han sido enviados con ajax le estare agradecido.

Fabicho10

22/1/2016
sssssssssss
sasa
sa
s
a
s

as
a

Fabicho10

22/1/2016
recibe.php
los valores q llegan a recibe.php son los siguientes
1. llega como POST, name..... name va dentro de los corechetes
2. llega como FILES archive1....... archive1 va dentro de los corechetes

2. llega como FILES archive2...... archive2 va dentro de los corechetes
los e puesto asi x q no me deja comentar como se deve esta paguina desarrolloweb.com

jmsierra

25/2/2016
Muy bien
Probado con django y funciona.

En django, los datos del formulario se reciben con request.POST y request.FILES.
Si respondes con un json, hay que quitar dataType: "html".

Gracias por el tuto, me ha servido bastante.

Julian Lasso

29/2/2016
Mil gracias por el POST
Hola compadre desde Colombia.
Te doy muchas gracias por el post, pues me ha sido de gran ayuda. Por mi parte, estoy usando AngularJS y llevo como 3 días buscando una solución con el mismo AngularJS y no encuentro nada a parte de complicados códigos. Ya miré mi registro en NodeJS y me llegan los datos perfectos.
Nuevamente mil gracias por tu aporte.

Jeremías

16/3/2016
10 puntos!!
Anduvo perfectamente!! gracias por el aporte!!! me sirvió mucho.
Por si a alguien le sirve, probé el ejemplo con Java usando struts y jBoss6. Desde el lado del controller, el action que recibe el post, tomará el formulario enviado (dataForm) en su parámetro form, que debe castearse al tipo de formulario que cada uno haya declarado en el archivo strus-config.xml. Este tipo de formulario debería tener un atributo del tipo FormFile, en el cual viajará almacenado el archivo subido. En fin, se trabaja exactamente igual que si se hiciera un submit comúm, pero en este caso se hace el post por ajax.

HAROLD

22/4/2016
VALOR DEL CAMPO DE TEXTO NOMBRE
Pana como hago para capturar le valor del campo de texto nombre?

Jamil Haro

02/6/2016
Consulta extra
Pues de ante mano gracias por el post, muy bueno envio y recibo info por ajax a php, pero si quiero solo enviar texto no me envia.. debo enviar imagen y texto eh tratado modificar el php pero el problema esta en ajax.. me puedes ayudar con esa duda?

Kevin

18/6/2016
SILENCIO!
Si no saben PHP como para saber subir un archivo mejor cállense y váyanse.

Programador

18/6/2016
Pregunta, pero de verdad.
Ok, muchas gracias, esto se ve muy útil, pero he aquí una pregunta, es obligatorio usar el FormData? no puedo usar un JSON así:
var data = {
nombre:valor
};

o aunque sea usar la función serialize()

además, no se me ocurre como usando append mandar el archivo, que pongo en valor? no me queda claro, comienzo a pensar que es obligatorio pasarle el form como argumento en el constructor.

Diego A. Zapata Häntsch

10/7/2016
Gracias
Excelente explicación. Me sirvió mucho.
Gracias Nuevamente!!!

Jrz04

12/7/2016
Muy buena ayuda... pero como se capturan en struts?
El post es de mucha ayuda... sin embargo, alguien podría decirme como obtener el "formData" desde struts2?, ya que si se realizo el submit normal los datos llegan correctamente pero si uso Ajax los valores llegan como null, entonces si uso struts como capturo los archivos enviados en el Action?

oso gomez

19/7/2016
codigo que falta
Yo tengo el archivo que falta el que lo necesite me escribe a mi correo ingoscargomez@hotmail.com
xq estoy intentando subir el archivo y nose que pasa no me deja la web. Me parece una #"###$%%& que no pueda subirlo. :)

YORSH

28/7/2016
COLOCAR IMAGEN DE CARGA
¿Cómo puedo agregar a ese codigo para que muestre una imagen de carga hasta finalizar el proceso del php?

William

24/8/2016
Excelente
Excelente

JODARICA

02/10/2016
buenisimo
Muchas gracias por el aporte lo modifique un poco y lo aplique a mi proyecto

root

30/10/2016
recibe.php
fino el codigo pero como llegan los valores al recibe.php
por favor, si es tan amable xD

Nestor

23/11/2016
como llegan los valores al recibe.php
Al llamar a recibe.php, los valores le son enviados, y ... son recibidos en aquel script mediante el $_POST, que es un Array que contiene todos los pares de valores del formulario que lo llamó.
Los pares se envían con el botón submit y se recibirán por recibe.php, pero... JQuery, intercepta el envío de submit, lo deja sin efecto, y lo envía realmente con ajax, con $.ajax, por eso no se actualiza la ventana del formulario, peero, en realidad actualiza el div de mensaje, con el contenido que el recibe.php le haya devuelto, y eso no es más que un echo que programas como respuesta para que te informe si todo llegó bien, o un valor que estabas pidiendo basado en lo que enviaste.
Busca $_POST de PHP, y JQuery.ajax, saludos

jmruizab

25/11/2016
recibe.php
Genial, gran aporte, para los que aun no puedan ver los archivos recibidos:
<?php
// Array POST
print_r($_POST);
echo "<br/><br/>";
// Array de los archivos:
print_r($_FILES);
?>

La manipulación ya depende de cada uno.
Saludos.

gabriella

06/1/2017
respuesta
gracias muy buen aporte

Franklin

24/1/2017
Se puede poner un loader mientras se carga la imagen antes de que salga el mensaje de completo
Hola amigo me gusto y ayudo mucho tu post.

Ahora mi pregunta es se peude agregar un loader o cargando imagen mientras se sube la imagen al servidor?

Si es asi puedes ayudarme cone l codigo.


Gracias desde ya;.

Saludos desde Ecuador

Abrahanns Hernández

06/5/2017
Ayuda
Esta línea porque es indispensable que este en el código.
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>

Yo ya utilizo jquery jquery-3.2.1.js en mi documento pero no la acepta, es necesario incluir la anterior, porque?

FormData solo funciona con esa versión de jquery o que amigos? Disculpen mi ignorancia y de antemano muchas gracias

leandro

25/10/2017
Gracias
Amigo muchas gracias.... esta super bueno el dato, me funciono sin problemas.

Eduardo

23/12/2017
De maravilla!
Funciona perfecto, simple y conciso.
Gracias !!

daniel

18/4/2018
me retorna un valor vacio mi ajax
hola que tal intengo pasa un valor de esta manera pero al imprimir en ajax me lo retorna vacio
js
var formData = new FormData($("#uploadimage")[0]);

// var datos = new FormData();
formData.append("idmostrar","si hay un valor aqui");
/*formData.append("idutilizar",id);
formData.append("productonombre",nombre);
formData.append("cantidad",cantidad);
formData.append("categoria",categoria);
formData.append("iva",iva);
formData.append("precio",precio);
formData.append("preciob",preciob);
formData.append("descripcion",descripcion);
formData.append("sustancia",sustancia);*/
// formData.append("idseleccionado",idseleccionado );
// request.send(formData);
var ruta = "views/modules/ajax5.php";
$.ajax({
url: ruta,
type: "POST",
dataType: "html",
data: formData,
contentType: false,
processData: false,
success: function(datos)
{
respuesta.innerHTML=datos;
id="";
}
});
y en ajax lo resivo asi pero no me muestra nada

if(isset($_FILES["file"]))
{
if(isset($_POST["idmostrar"]))
{
var_dump($_POST["idmostrar"]);
}
else
{
echo "no esta retornando ningun valor";
}
/*$a = new Ajax5();
//$a->mensaje= $_POST["mensajechat"];
$a->idproducto= $_POST["idseleccionado"];
$a->actualizarproductos();*/

}

RickDevelop

23/5/2018
Super cool!
Grandioso código hermano <3, lo he probado en asp net mvc c# y ha funcionado de maravilla, al final de cuentas todo es jquery o java script, y bueno, creo que tutoriales de como recibir un file en php hay demasiados como para que te quieran preguntar eso, pero el código funciona 100% real no fake, saludos y gracias por compartir tan grandioso articulo hermano(porque si, lo leí todo y no solo vine por el código).

Arturo

24/9/2018
Gracias
Muy bueno el ejemplo

RICARDO

12/10/2018
RECIBE.PHP
BUENO EL TUTORIAL PERO SE OLVIDÓ EL RECIBE.PHP
SOLO HAGAN UN ARCHIVO ASI:

<?php
print_r($_FILES);
?>

Y VERAN LOS DATOS RECIBIDOS