File Upload (asynchronous & multiple)

Antes del HTML5 uno veía plugins como uploadify para subir archivos y de entrada te sorprendías, después analizabas el código y te dabas cuenta que la magia era posible gracias al plugin de Flash o al de Silverlight que te permitían seleccionar múltiples archivos, ahora con la llegada de HTML5 el reto de eliminar todos los plugins sigue su curso.

Para empezar ahora tenemos File API, la cual nos permite tener mayor control sobre la interacción con archivos de lado del cliente, a eso le agregamos que el control input (type=file) ahora soporta el atributo multiple lo que ya habilita la opción de seleccionar muchos archivos con el mismo control… Creo que no hay mucho que decir así que si les aburre la teoría aquí está un ejemplo práctico…

Necesitaremos un control file y una lista donde desplegar nuestros archivos a cargar:

<!-- "multiple" - Con esto ya tenemos habilitada la selección de múltiples archivos -->
<input id="files" type="file" multiple="multiple" />
<ul id="file-list"></ul>

En cuanto el uso del API hay que validar que el navegador soporte esta funcionalidad, esto se logra validando lo siguiente:

var loadable = window.File && window.FileReader && window.FileList && window.Blob;

Si todo existe podemos explotar al máximo el API.

Crearemos ahora la carga asíncrona de los archivos, para eso cuando cambie nuestra selección de archivos mandaremos llamar una función como esta:

function uploadFile(file) {

    xhr = new XMLHttpRequest();

    // Actualizamos progreso de carga
    xhr.upload.addEventListener("progress", function (event) {
        if (event.lengthComputable) {
            // Código
        }
    }, false);

    // Actualizamos cuando se termine de cargar el archivo
    xhr.addEventListener("load", function (result, d) {
        // Código
    }, false);

    // Mandamos el archivo a nuestro controlador
    xhr.open("post", "Uploader.ashx", true);

    // Creamos un form con el archivo a enviar
    var fd = new FormData();
    fd.append("file", file);

    // Enviamos el archivo (de forma asíncrona)
    xhr.send(fd);

}

Todo es posible gracias a los siguientes elementos:

XMLHttpRequestNos permite crear un objeto para intercambiar datos con el servidor

FormDataNos permite crear un formulario dinámico para poder enviarlo

Del lado del servidor crearemos un manejador muy simple que permitirá procesar cada archivo y quedaría algo como:

public void ProcessRequest( HttpContext context ) {            

    foreach ( string key in context.Request.Files ) {
        HttpPostedFile file = context.Request.Files[ key ] as HttpPostedFile;
        if ( file.ContentLength == 0 )
            continue;

        FileInfo fileInfo = new FileInfo( file.FileName );
        //file.SaveAs( context.Server.MapPath( filePath + fileInfo.Name ) );
        context.Response.Write( "Archivo guardado correctamente" );
    }

}

Si se agrega un poco de estilo y algunos elementos nuevos como el tag progress se pueden lograr cosas muy interesantes. Pueden ver el demo propuesto desde aquí (por seguridad ningún archivo que se adjunte se guarda en el servidor únicamente se simula la carga y el envió al servidor)

Conclusión

HTML5 gana una estrella más en cuanto a la integración de herramientas para desarrollo sin el uso de plugins, si bien esto es relativamente nuevo creo que comenzaremos a ver controles más complejos y sobre todo libres de uso ya que hay muchas herramientas para comenzar a crear.

Comparte tus creaciones en este espacio.

7 respuestas a «File Upload (asynchronous & multiple)»

  1. Vientos, Charly, ahora si te rifaste, lástima que en la chamba aún no llega el progreso, solo usan IE8 😦
    Estaría bien saber que porcentaje de usuarios usan navegador con soporte de HMTL5 para ver si vale la pena.

    1. Pues viene fuerte el boom de HTML5, tanto que Microsoft se tuvo que poner las pilas y en su versión 10 ya tiene un 85% de compatibilidad con el HTML5, en cuanto a usuarios de Chrome, FireFox, Safari,… no le veo tanto problema porque desde antes que se liberara oficialmente el HTML5 ya lo soportaban 😀

    1. Es que como es un sitio «nuevo» ni te imaginas la cantidad de mensajes spam que me llegan, por cada comentario que veas llegan como 20 de spam :S y después de ponerle el validar ya es menos jeje, que se supone que si te firmas con una misma cuenta de correo y te apruebo un mensaje después ya no necesita moderación, no te ha pasado así?

  2. Carlos:
    Estuve tratando de hacerme de un fileupload con tu manual,…pero no pude conectar el evento javascript con el code behind de la pagina de .net,…estoy tratando de hacerlo con Formularios en VB webdeveloper 2015

    1. Hola Manuel, en el ejercicio que hice la pagina que interactúa con el JavaScript es un «Generic Handler» que es el archivo Upload.ashx que viene declarado en el ejemplo y se encuentra en la misma ruta que el archivo de ejemplo, no debe haber problema, si no usas un Generic Handler posiblemente haya que hacer unos pequeños ajustes para que puedas procesar el archivo, si no te resulta mándame el código de tu ejemplo para revisarlo.

  3. para el loader de JavaScript usa esto de css y quita el método center:

    #loader { display: none; width: 100%; height: 100%; position:fixed; top: 0; left: 0; background-color: rgba(0,0,0,.8); text-align: center; z-index: 999999; }
    #loader > div { min-height: 50px; margin: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); -moz-transform: translate(-50%, -50%); -ms-transform: translate(-50%, -50%); padding: 12px; width: 300px; height: auto; background-color: rgba(255, 255, 255, .5); border-radius: 4px; border: solid 4px #fff; }
    #loader > div > div { display: block; color: #fff; font-weight:bold; font-size: 12px; }
    #loader > div > p { display: block; width: 160px; height: 16px; margin: 0 auto; border-radius: 2px; border:none; margin-top: 16px; background: transparent url(../img/loader.gif) no-repeat center center; }

Deja un comentario