0

I'm working on a file uploader where I want my users to be able to upload multiple files at the same time, and multiple files one by one. I saw a lot of other pages with similar questions, but none of them could solve my problem.

This is my html upload Form:

<form id="myform" action="upload.php" method="post" enctype="multipart/form-data" >
  <h3>Upload File</h3>
  <input type="file" name="myfile[]" id="uploadFile" multiple> 
  <button type="submit" id="mySubmitButton" onclick="saveData()" name="save">UPLOAD</button>
</form>

I think FormData is the right approach for my case, but I'm not sure. I want to make an array of the files and send them through a PHP file, where they are sent to a server. I really don't want to use ajax.

This is my Javascript code:

<script>

function saveData(){
  formData.getAll("myfile[]");
}

$('#uploadFile').on('change', function() {
  var formData = new FormData();
  var files = $('#uploadFile')[0].files;
  for (var i = 0; i < files.length; i++) {
    formData.append('myfile[]', document.getElementById('uploadFile').files[i]);
  }    
});

</script>

This isn't working. Now I only upload the last selected file. Hope you can help me, thanks in advance!

4
  • when you say "multiple files one by one" does that mean sequentially (pick all and upload 1,2,3... ) or individually(pick file -> upload, pick another -> upload etc )? Commented Aug 21, 2021 at 12:17
  • I want to upload the files sequentially, so, select file -> select another -> select another -> upload. Now, if I select the files sequentially, only the last file gets uploaded because it overwrites the current selection. Commented Aug 21, 2021 at 12:31
  • OK - makes sense but the FormData use does not - how are you going to use that if you do not use Ajax? Commented Aug 21, 2021 at 12:33
  • What would a solution with Ajax look like? Commented Aug 21, 2021 at 12:36

2 Answers 2

1

Try changing to this:

$('#uploadFile').on('change', function() {
  var formData = new FormData();
  var files = $('#uploadFile').files;
  for (var i = 0; i < files.length; i++) {
    formData.append('myfile[]', files[i]);
  }    
});
Sign up to request clarification or add additional context in comments.

1 Comment

This still uploads only the last selected file :(, thanks though.
0

The general idea would be to create a global variable ( or within the scope of an anon function perhaps ) and add each newly selected file to that array. When the button is clicked process this array by sending an ajax request to upload the file. By using Promises you can let the user know when all the files have been uploaded.

The snippet will not work here as there is no PHP to process the request but the full example works OK.

// keep track of selected files in this array
let files=[];
let promises=[];

// various form elements
const form=document.forms.uploader;
const bttn=form.save;
const input=form.querySelector('input[name="myfile[]"]');

// event handler to add selcted files to array - one or more at a time
input.addEventListener('change',function(e){
  for( let i=0; i < this.files.length; i++ ) files.push( this.files[i] );
});


// event handler to process button click. Ajax request sent using Fetch
// result echoed to console only
bttn.addEventListener('click',function(e){
  e.preventDefault();

  let fd=new FormData();

  // create a new Promise for each file and upload. Resolve on success
  files.forEach( file =>{
    console.info( 'Promise to upload:%s', file.name )
    /*
    fd.set('file',file);

    promises.push( new Promise((resolve,reject)=>{
      fetch( form.action, { method:'post', body:fd } )
      .then( r=>r.json() )
      .then( json=>resolve( json ) )
      .catch( err=>reject( err ) )                    
    }))
    */
  })

  // process all files and display results
  /*
  Promise.all( promises )  
  .then( results=>console.log(results) )
  .catch( err=>alert(err) )
  */
});
<!-- form action removed for testing only -->
<form name='uploader' action='' method='post'><!-- upload.php -->
  <h3>Upload File</h3>
  <input type='file' name='myfile[]' multiple /> 
  <button type='submit' name='save'>UPLOAD</button>
</form>

Full example in single page:

<?php
    if( $_SERVER['REQUEST_METHOD']=='POST' ){
        ob_clean();
        
        $savepath=sprintf('%s/uploads',__DIR__);

        if( !empty( $_FILES['file'] ) ){
            $obj=(object)$_FILES['file'];
            $tmp=$obj->tmp_name;
            $name=$obj->name;
            $size=$obj->size;
            $type=$obj->type;
            $error=$obj->error;
            
            if( $error==UPLOAD_ERR_OK ){
                $targetfile=sprintf('%s/%s',$savepath,$name);
                $bytes=move_uploaded_file($tmp,$targetfile);
                
                $data=array(
                    'name'  =>  $name,
                    'size'  =>  $size,
                    'type'  =>  $type,
                    'bytes' =>  $bytes,
                    'file'  =>  $targetfile
                );
                exit( json_encode( $data ) );               
            }
            

        }
        exit();
    }
?>

<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title></title>
    </head>
    <body>
    
        <!-- form action removed for testing only -->
        <form name='uploader' action='' method='post'><!-- upload.php -->
            <h3>Upload File</h3>
            <input type='file' name='myfile[]' multiple /> 
            <button type='submit' name='save'>UPLOAD</button>
        </form>
    
        <script>
            
            // keep track of selected files in this array
            let files=[];
            let promises=[];
            
            // various form elements
            const form=document.forms.uploader;
            const bttn=form.save;
            const input=form.querySelector('input[name="myfile[]"]');
            
            // event handler to add selcted files to array - one or more at a time
            input.addEventListener('change',function(e){
                for( let i=0; i < this.files.length; i++ ) files.push( this.files[i] );
            });
            
            
            // event handler to process button click. Ajax request sent using Fetch
            // result echoed to console only
            bttn.addEventListener('click',function(e){
              e.preventDefault();
              
              let fd=new FormData();
              
              // create a new Promise for each file and upload. Resolve on success
              files.forEach( file =>{
                  console.info( 'Promise to upload:%s', file.name )
                  fd.set('file',file);
                  
                  promises.push( new Promise((resolve,reject)=>{
                      fetch( form.action, { method:'post', body:fd } )
                        .then( r=>r.json() )
                        .then( json=>resolve( json ) )
                        .catch( err=>reject( err ) )                      
                  }))
                  
              })
              
              // process all files and display results
              Promise.all( promises )  
                .then( results=>{ console.log(results);files=[];} )
                .catch( err=>alert(err) )
            });
        </script>
    </body>
</html>

6 Comments

Thank you for your answer! I can see the promises in the console, but the upload button is still disabled. Do you have any idea why that is happening?
the button cannot be disabled otherwise you'd not be able to send the request initially.
You're right, sorry. Uploading the files doesn't work. I get this error in the console: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0.
You get that specific error when using the code as posted - including PHP? If yes - did you modify the savepath to suit your environment?
Is there a way to get the 'files' array values into the file input (form) instead of the console?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.