Enviar archivos con AJAX y jQuery en HTML5

Con la evolución de los navegadores y la llegada de HTML5 ya no es necesario utilizar librerías extras para simular subir archivos por AJAX, la mayoría de estas librerías lo que hacían era utilizar FLASH o hacer un IFRAME para capturar esta subida de archivos. Con HTML5 ya no es necesario esto.

gela1

Esto es gracias a la introducción del objeto FormData que nos permite crear formularios al vuelo.

Asignar un formulario existente a un objeto FormData:

var formElement = document.getElementById("someFormElement");
 
var formData = new FormData(formElement);

O puedes recorrer el formulario con jQuery para solo agregar los campos que te interesan:

var formData = new FormData();
$('#someFormElement :input').each(function(){
        var input = $(this);
        switch (input.attr('type')){
            case "checkbox":
                var v = (input.is(":checked"))?1:0;
                formData.append(input.attr('name'), v);
                break;
            case "file":
                $.each(input.prop("files"),function(i,file){
                    formData.append(input.attr("name"), file);
                });
                break;
            default:
                if(!input.is(":disabled")){
                    formData.append(input.attr('name'), input.val());
                }
        }
});

Nótese que para recorrer los archivos para cada elemento file utilizo un each, esto es para permitir subir múltiples archivos en un mismo input (el nombre debería llevar corchetes para poder ser interpretado como un array de archivos):

<input type="file" name="attachment[]" multiple="multiple" />

Pero no solo es posible obtenerlos de un formulario sino que también es posible adjuntar archivos al vuelo si sabemos su ubicación:

formData.append('attachment_form_name', '@'+filepath);

Nota: de esta forma los otros campos como name del archivo se pierden al ser enviados por el post, solo llegaría el tmp_name para poder subirlo correctamente. La solución sería crear un objeto file de JavaScript. Es muy importante la arroba [@] delante de la ruta del archivo.

Muy bien. con esto ya tenemos los archivos seleccionados por el usuario o asignados dinámicamente en nuestro formulario. ¿Cómo lo enviamos por AJAX?

Envío del objeto FormData por AJAX convencional

var xhr = new XMLHttpRequest();
 
xhr.open("POST", "http://some.url/");
 
xhr.send(formData);

Envío del objeto FormData por AJAX con jQuery

$.ajax({
                type: "POST",
                url: "http://some.url/",
                data: post,
                async: false,
                cache: false,
                contentType: false,
                processData: false,
                dataType: "json",
                success: function(json){
                   
                }
});

Nota: para hacerlo con jQuery es sumamente importante no cambiar los valores del ejemplo para cache, contentType y processData.

Y listo, de esta forma recibiremos los archivos por POST y podrán ser procesados como si hubiésemos pulsado el botón submit, una sencilla manera de enviar archivos por AJAX utilizando FormData sin necesidad de FLASH ni IFRAMES.

Comentarios