HTML5 – Upload di file con XMLHttpRequest 2

L’upload di file tramite pagine web come, ad esempio, il caricamento degli allegati ad una email, oppure le immagini da caricare in una gallery, ecc…, è spesso tra i pensieri di molti web developers. Durante i primi anni del web, l’upload di file era gestito semplicemente da un form inviato ad un’altra pagina web: il browser ricaricava completamente la pagina impostata nell’action del form. Questo metodo andava, e va ancora, bene per siti semplici o istituzionali nei quali l’invio di form non è l’aspetto essenziale a livello quantitativo per le prestazioni del software.

Per quanto riguarda, invece, software più complessi come web apps, gli sviluppatori hanno subito adottato nuove tecniche per la gestione dei form. Ajax ha cambiato il modo di realizzare software per il web. Il metodo classico per il caricamento di file è stato, ed in gran parte è ancora, l’invio del form ad un un iframe nascosto (fake ajax), che, impostato come target contenesse  lo script server side per la manipolazione dei dati. Tramite questa procedura la pagina principale non viene ricaricata e, dunque, l’invio dei dati risulta più performante rispetto al passato.

Oggi voglio analizzare il prossimo passo nella gestione dei form che, grazie alle nuove tecniche HTML5 e XMLHttpRequest 2 permette un caricamento ancora più veloce e maneggevole anche per i file.

La struttura del form Html5

Ho voluto realizzare il form html5 con una struttura veramente semplice come è bene predisporre per i primi test con le nuove tecnologie ed anche perchè il grosso del lavoro è gestito dal codice Js.

<form id="form1" enctype="multipart/form-data" method="post" action="filesystem/upload">
    <label for="fileToUpload">Seleziona i file da caricare:</label>
    <input type="file" name="fileToUpload" id="fileToUpload" multiple />
<div id="fileInfo"> </div>
    <input type="submit" id="fileUpload" value="Upload" />
<div id="progressNumber"> </div>
</form>

L’unica minuscola particolarità degna di nota è l’utilizzazione della proprietà multiple per l’input[type=”file”]. Grazie a questa proprietà html5 i browser moderni permettono di caricare più file contemporaneamente attraverso un unico campo di input.

Visualizzare i dati dei file

Il primo step da realizzare con javascript per offrire un miglior controllo del flusso di caricamento all’utente è elencare le informazioni tecniche dei file selezionati prima del caricamento:

Visualizzare i file selezionati con Javascript

Per predisporre la visualizzazione delle informazioni tecniche tramite Js ci viene in aiuto la specifica FileAPI di HTML5. Avendo il riferimento all’input per la selezione dei file possiamo accedere all’oggetto FileList contenente la lista dei file selezionati: una collezione di oggetti di tipo File. Le proprietà dell’oggetto File sono:

  1. name: il nome del file
  2. type: il mime type del file
  3. size: la dimensione del file in bytes

Il codice javascript corrispondente:

fselected: function() {
    var fileinfo = '';
    var files = this.element.files;
    for (xx=0;xx<files.length;xx++) {         
        var file=files[xx];
         var fileSize = 0;
         if (file.size > 1024 * 1024) 
            fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
        else 
            fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
        fileinfo += " " + 'Name: ' + file.name + '<br />Size: ' + fileSize + '<br />Type: ' + file.type + "";
    }
    if (this.fileinfo==undefined)
        this.fileinfo = new Element('div',{
            'class':'fileinfo'
        }).inject(this.element, 'after');
    this.fileinfo.set('html',fileinfo);
}

fselected è il metodo della classe Js che abbiamo creato per la gestione del form. Per comodità ho utilizzato alcune istruzioni della libreria Mootools che recentemente è arrivata alla versione 1.3.2. Questo metodo viene richiamato all’evento onchange dell’input[type=”file”] inserito nel nostro form. L’elemento in questione è identificato, nella nostra classe come this.element. L’istruzione this.element.files restituisce tutti i file che sono stati selezionati per la suddetta input e ciclando questi dati otteniamo ogni singolo elemento, dal quale recuperare le proprietà name, size e type.

L’invio del form

La parte più interessante della classe Js realizzata è quella legata all’invio del form e la gestione della percentuale di progressione nel caricamento dei dati:

upload: function(e){
    e.stop();
    var data = new FormData();
    var files = this.element.files;
    for (xx=0;xx<files.length;xx++) {
        data.append("file["+xx+"]", files[xx]);
    }
    var xhr = new XMLHttpRequest();
    xhr.upload.addEventListener("progress", this.uploadProgress.bind(this), false);
    xhr.addEventListener("load", this.uploadComplete.bind(this), false);
    xhr.addEventListener("error", this.uploadFailed.bind(this), false);
    xhr.addEventListener("abort", this.uploadCanceled.bind(this), false);
    xhr.open("POST", this.url);
    xhr.send(data);
},
uploadProgress: function(evt) {
    if (evt.lengthComputable) {
        var percentComplete = Math.round(evt.loaded * 100 / evt.total);
        document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
    }
    else {
        document.getElementById('progressNumber').innerHTML = 'unable to compute';
    }
},
uploadComplete: function(evt) {
    alert(evt.target.responseText);
},
uploadFailed: function(evt) {
    alert("Errore durante il caricamento del file.");
},
uploadCanceled: function(evt) {
    alert("Upload cancellato dall'utente oppure connessione interrotta dal browser.");
}

Il metodo upload viene chiamato al click sul input[type=”submit”] incluso nel form. La classe FormData istanziata è supportata da XMLHttpRequest 2 ed è un oggetto utile per definire un elenco di dati definiti secondo lo stile coppia key/value tramite il metodo append(). Il metodo upload e gli altri da esso richiamati tramite listener per i vari eventi legati al caricamento sono semplici e di comprensione intuitiva.
Menzione va fatta per la gestione dell’indicatore di progressione dell’invio applicato all’evento progress e che, tramite i valori loaded e total offerti dall’evento passato al metodo uploadProgress. Questi valori ci dicono la quantità di informazioni caricate rispetto a quelle totali da inviare tramite il form: così è possibile gestire il valore per tracciare la percentuale del caricamento in vari modi, come barra di caricamento o semplice percentuale stampata.

Il form in caricamento con la percentuale di caricamento

Cliccando qui è possibile scaricare la classe realizzata che richiede il caricamento di Mootools 1.3.2

Lascia un commento

Tutti i campi sono obbligatori.
L'indirizzo email non verrà pubblicato