2012-12-01 12 views
24

Ho un più file caricare forma:HTML5 upload di file multipli: caricare uno per uno attraverso AJAX

<input type="file" name="files" multiple /> 

Vi metto questi file con l'Ajax. Vorrei caricare i file selezionati uno per uno (per creare singole barre di avanzamento e per curiosità).

posso ottenere l'elenco dei file o singoli file da

FL = form.find('[type="file"]')[0].files 
F = form.find('[type="file"]')[0].files[0] 

yieling

FileList { 0=File, 1=File, length=2 } 
File { size=177676, type="image/jpeg", name="img.jpg", more...} 

Ma FileList è immutabile e non riesco a capire come presentare il singolo file.

Penso che sia possibile perché ho visto http://blueimp.github.com/jQuery-File-Upload/. Non voglio usare questo plugin, visto che è tanto l'apprendimento come risultato (e che avrebbe bisogno di essere troppo conservativo in ogni caso). Inoltre non voglio usare Flash.

risposta

26

Per fare in modo che sia un'operazione sincrona, è necessario avviare il nuovo trasferimento quando l'ultimo è terminato. Gmail, ad esempio, invia tutto in una volta, contemporaneamente. L'evento per lo stato di avanzamento del caricamento di file AJAX è progress o onprogress nell'istanza di tipo XmlHttpRequest.

Quindi, dopo ogni $.ajax(), sul lato server (che non so cosa si utilizzerà), inviare una risposta JSON per eseguire AJAX sull'ingresso successivo. Un'opzione sarebbe quella di associare l'elemento AJAX a ciascun elemento, per semplificare le cose, quindi è sufficiente farlo, nello success dello $(this).sibling('input').execute_ajax().

Qualcosa di simile a questo:

$('input[type="file"]').on('ajax', function(){ 
    var $this = $(this); 
    $.ajax({ 
    'type':'POST', 
    'data': (new FormData()).append('file', this.files[0]), 
    'contentType': false, 
    'processData': false, 
    'xhr': function() { 
     var xhr = $.ajaxSettings.xhr(); 
     if(xhr.upload){ 
     xhr.upload.addEventListener('progress', progressbar, false); 
     } 
     return xhr; 
    }, 
    'success': function(){ 
     $this.siblings('input[type="file"]:eq(0)').trigger('ajax'); 
     $this.remove(); // remove the field so the next call won't resend the same field 
    } 
    }); 
}).trigger('ajax'); // Execute only the first input[multiple] AJAX, we aren't using $.each 

Il codice di cui sopra sarebbe per più <input type="file"> ma non per <input type="file" multiple>, in questo caso, dovrebbe essere:

var count = 0; 

$('input[type="file"]').on('ajax', function(){ 
    var $this = $(this); 
    if (typeof this.files[count] === 'undefined') { return false; } 

    $.ajax({ 
    'type':'POST', 
    'data': (new FormData()).append('file', this.files[count]), 
    'contentType': false, 
    'processData': false, 
    'xhr': function() { 
     var xhr = $.ajaxSettings.xhr(); 
     if(xhr.upload){ 
     xhr.upload.addEventListener('progress', progressbar, false); 
     } 
     return xhr; 
    }, 
    'success': function(){ 
     count++; 
     $this.trigger('ajax'); 
    } 
    }); 
}).trigger('ajax'); // Execute only the first input[multiple] AJAX, we aren't using $.each 
+4

nota che questo codice è stato progettato per i browser moderni davvero che supportano formdata e XMLHttpRequest2 soltanto, nessun hack per i vecchi browser – pocesar

+4

chiedevo perché sembra così delizioso ...;) – Selosindis

+5

Creazione di una nuova 'forma' e l'aggiunta di file uno per uno usando '(nuovo FormData()). append ('file', this.files [count])' era quello che stavo cercando, grazie! – Mark

7

This looks like a very good tutorial, just what you're looking for.

Ciò premesso, il caricamento tramite vanilla ajax non è supportato in tutti i browser e si consiglia comunque di utilizzare uno iframe. (I.E crea dinamicamente un iframe e POST usando javascript)

I have always been using this script e lo trovo molto conciso. Se vuoi imparare come caricare creando un iframe, dovresti scavare attraverso la fonte.

Speranza che aiuta :)

modificare Extra

Per creare barre di avanzamento con il metodo iframe, è necessario fare un certo lavoro sul lato server. Se stai usando PHP, è possibile utilizzare:

Se l'uso nginx si può anche scegliere di compilare con la loro Upload progress module

Tutti questi funzionano allo stesso modo - ogni caricamento non è un UID, si chiederà per il 'progresso' associato a tale ID a intervalli regolari via ajax. Ciò restituirà l'avanzamento del caricamento come determinato dal server.

+0

Il primo collegamento era davvero un buon tutorial sugli oggetti FormData, grazie! – Mark

1

Stavo affrontando lo stesso problema e sono arrivato con questa soluzione. Riesco semplicemente a recuperare il modulo con multipart, e in una chiamata ricorsiva (file dopo file) avviare una richiesta Ajax, che chiama solo dopo quando è fatto.

var form = document.getElementById("uploadForm"); 
var fileSelect = document.getElementById("photos"); 
var uploadDiv = document.getElementById("uploads"); 

form.onsubmit = function(event) { 
    event.preventDefault(); 

    var files = fileSelect.files; 
    handleFile(files, 0); 
}; 

function handleFile(files, index) { 
    if(files.length > index) { 
     var formData = new FormData(); 
     var request = new XMLHttpRequest(); 

     formData.append('photo', files[ index ]); 
     formData.append('serial', index); 
     formData.append('upload_submit', true); 

     request.open('POST', 'scripts/upload_script.php', true); 
     request.onload = function() { 
      if (request.status === 200) { 
       console.log("Uploaded"); 
       uploadDiv.innerHTML += files[ index ].name + "<br>"; 
       handleFile(files, ++index); 
      } else { 
       console.log("Error"); 
      } 
     }; 
     request.send(formData); 
    } 
} 
+0

Questo non è quello che è stato chiesto. L'OP ha chiesto di caricare i file selezionati uno a uno con le singole barre di avanzamento. Downvoted. – TheCarver