web-dev-qa-db-fra.com

Téléchargement de plusieurs fichiers HTML5: téléchargez un à un AJAX

J'ai un formulaire de téléchargement de plusieurs fichiers:

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

Je poste ces fichiers avec ajax. Je souhaite télécharger les fichiers sélectionnés un par un (pour créer des barres de progression individuelles et par curiosité).

Je peux obtenir la liste des fichiers ou des fichiers individuels en

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...}

Mais FileList est immuable et je ne vois pas comment soumettre un fichier unique.

Je pense que cela est possible car j'ai vu http://blueimp.github.com/jQuery-File-Upload/ . Je ne veux cependant pas utiliser ce plugin, car il s'agit autant de l'apprentissage que du résultat (et il faudrait de toute façon trop de personnalisation). Je ne veux pas non plus utiliser Flash.

27
Mark

Pour que cette opération soit synchrone, vous devez lancer le nouveau transfert à la fin du dernier transfert. Gmail, par exemple, envoie tout en même temps, simultanément. L'événement pour la progression du téléchargement du fichier AJAX est progress ou onprogress sur l'instance brute XmlHttpRequest

Ainsi, après chaque $.ajax(), côté serveur (que je ne sais pas ce que vous allez utiliser), envoyez une réponse JSON pour exécuter le AJAX à la prochaine entrée. Une option consisterait à lier l’élément AJAX à chaque élément, pour faciliter les choses, afin que vous puissiez simplement le faire, dans la variable success la $(this).sibling('input').execute_ajax().

Quelque chose comme ça:

$('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

Le code ci-dessus serait pour plusieurs <input type="file"> mais pas pour <input type="file" multiple>, dans ce cas, il devrait être:

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 
30
pocesar

Cela ressemble à un très bon tutoriel, exactement ce que vous cherchez .

Cela dit, le téléchargement via Vanilla ajax n'est pas pris en charge par tous les navigateurs, et je recommanderais quand même l'utilisation de iframe. (I.E crée dynamiquement un iframe et POST en utilisant javascript)

J'ai toujours utilisé ce script et je le trouve très concis. Si vous souhaitez apprendre à télécharger en créant un iframe, vous devez creuser avec sa source.

J'espère que ça aide :)

Extra edit

Pour créer des barres de progression avec la méthode iframe, vous devez effectuer certaines tâches côté serveur. Si vous utilisez php, vous pouvez utiliser:

Si vous utilisez nginx, vous pouvez également choisir de compiler avec leur Télécharger le module de progression

Tout cela fonctionne de la même manière - chaque téléchargement a un UID, vous demanderez la «progression» associée à cet ID à des intervalles cohérents via ajax. Cela renverra la progression du téléchargement telle que déterminée par le serveur.

8
Nathan Kot

Je faisais face au même problème et suis venu avec cette solution. Je récupère simplement le formulaire avec multipart, et en appel récursif (fichier après fichier), lance la demande ajax, qui appelle seulement quand est terminé.

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 );
    }
}
4
Jakub Hluchý

En utilisant ce code source, vous pouvez télécharger plusieurs fichiers, comme Google, un par un à travers ajax. Aussi, vous pouvez voir la progression du téléchargement

HTML

 <input type="file" id="multiupload" name="uploadFiledd[]" multiple >
 <button type="button" id="upcvr" class="btn btn-primary">Start Upload</button>
 <div id="uploadsts"></div>

Javascript

<script>

function uploadajax(ttl,cl){

var fileList = $('#multiupload').prop("files");
$('#prog'+cl).removeClass('loading-prep').addClass('upload-image');

var form_data =  "";

form_data = new FormData();
form_data.append("upload_image", fileList[cl]);


var request = $.ajax({
          url: "upload.php",
          cache: false,
          contentType: false,
          processData: false,
          async: true,
          data: form_data,
          type: 'POST', 
          xhr: function() {  
      var xhr = $.ajaxSettings.xhr();
      if(xhr.upload){ 
        xhr.upload.addEventListener('progress', function(event){
                        var percent = 0;
                        if (event.lengthComputable) {
                            percent = Math.ceil(event.loaded / event.total * 100);
                        }
                        $('#prog'+cl).text(percent+'%')

                    }, false);
       }
      return xhr;
     }    
      })
      .success(function(res,status) {

        if(status == 'success'){

            percent = 0;
            $('#prog'+cl).text('');            

                $('#prog'+cl).text('--Success: ');

            if(cl < ttl){
                uploadajax(ttl,cl+1);
            }else{
               alert('Done ');

            }     

            }

      })
      .fail(function(res) {
      alert('Failed');
      });

}



$('#upcvr').click(function(){

var fileList = $('#multiupload').prop("files");
$('#uploadsts').html('');
var i
for ( i = 0; i < fileList.length; i++) {
$('#uploadsts').append('<p class="upload-page">'+fileList[i].name+'<span class="loading-prep" id="prog'+i+'"></span></p>');
if(i == fileList.length-1){
    uploadajax(fileList.length-1,0);
}
}

});

</script>

PHP

upload.php
    move_uploaded_file($_FILES["upload_image"]["tmp_name"],$_FILES["upload_image"]["name"]);
0
Milan Krushna