0

I'm trying to upload multiple pictures with javascript. I was able to get one picture to upload fine - but when I upload n pictures, it just uploads the first picture of the group n times. The code is as follows:

var field = document.getElementById('file-field')

field.addEventListener('change', function(data) {
  var files  = data.target.files

  for(var i=0; i<files.length; i++) {
    multipartPost('/photos/create', files[i]) // I've tried moving this out into another function, an IIFY, etc
  }
})

function multipartPost(url, params, callback) {
  var xml  = new XMLHttpRequest()
  var data = new FormData()
  data.append('file', params, false) // This is where I fixed it so it can at least upload synchronously by passing false as a third param

  xml.open('post', url)
  xml.send(data)

  xml.onreadystatechange = function() {
    if(xml.readyState===4) {
      if(xml.status===200) {
        console.log('success')
      } else {
        console.log(xml.status, "Error")
      }
    }
  }
}

Any idea on how to get it to upload ALL the pictures or why its repeatedly uploading the single picture n times?


A little more background:

I originally had a form which I would submit to upload a file, but then I decided to get it to upload through javascript. Turns out that it's really simple with XHR2, and I was able to successfully upload a file without a form - the html is simply

<input type="file" name="file" id="file-field" multiple />

However I decided to go to the next step and allow multiple uploads. I thought it would be as simple as changing files[0] to files[i] inside a for loop, but if I upload multiple files, it just takes the first file and uploads it n times, n being the amount of files that are in the file field.


Update

I was able to get the multiple file uploads using synchronous post requests, by passing a third parameter of value false to the function XMLHttpRequest.open, so there is definitely an error related to a-sync. I'll keep debugging but if anyone knows why it's not working asynchronously I'm very curious


Solution

var field = document.getElementById('file-field')

field.addEventListener('change', function(e) {
  var files  = e.target.files
  for(var i = 0; i < files.length; i++) {
    multipartPost('/photos/create', files[i], appendPhoto)
  }
})

function appendPhoto(data) {
  // Callback function
}

function multipartPost(url, params, callback) {
  var xml  = new XMLHttpRequest()
  var data = new FormData() // Using FormData allows me to keep my server-side code the same, just as if it were a form submission
  data.append('file', params)

  xml.open('post', url) // No third param will default to async: true
  xml.setRequestHeader("X-Requested-With","XMLHttpRequest") // This header allows me to recognize the request as xhr server side
  xml.send(data)

  xml.onreadystatechange = function() {
    if(xml.readyState===4) {
      if(xml.status===200) {
        callback(xml.responseText)
      } else {
        console.log(xml.status, "Error")
      }
    }
  }
}
cadlac
  • 2,802
  • 3
  • 18
  • 34
  • 1
    possible duplicate of [Javascript infamous Loop problem?](http://stackoverflow.com/questions/1451009/javascript-infamous-loop-problem) – epascarello Oct 23 '13 at 21:20
  • Can't you just attach all the files to the `FormData` object by passing in the `
    ` itself?
    – callmehiphop Oct 23 '13 at 21:23
  • Your code is riddled with errors and bad practices. The code you posted here won't work at all. Start by posting the actual code you are using. – Ray Nicholus Oct 23 '13 at 21:27
  • @epascarello Possibly, I saw that post but I've tried moving it out into another function, and every way I can think of. Plus it keeps uploading the first object, not the last, which threw me off again. – cadlac Oct 23 '13 at 22:17
  • @callmehiphop there actually is no form, I'm just grabbing the data straight from an input tag. Although that does make more sense to send them all at one time then deal with the looping server side. I'm still curious how to deal with sending off the different files though – cadlac Oct 23 '13 at 22:18
  • @RayNicholus This is the actual code, it does work for single file uploads, I did mess up the index right before I posted it - but besides that if you could point out the errors and bad practices that would be much appreciated – cadlac Oct 23 '13 at 22:21

2 Answers2

0

Code seems to be incorrect. Maybe after manual editing while posting: look at the for loop. There is "i" variable declared and used while inside the loop you use "index" variable. Also I see no callback param given. I am not sure that anything here is related to closure. What are you going to do with the help of this code?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
  • Sorry I just updated the i and index, that was my bad. If I get this to work I would add the callback param on success, but there's no reason to have one yet so I just have it blank. It's possible it's not related to closures, I'm baffled at what it's doing, I imagined it was something to do with closures or XHR2. And what I would like to do is send each file off to be uploaded on the server, but it will only upload one file, trying to do multiple just uploads 1 photo n times. I'll update the question to give some more background – cadlac Oct 23 '13 at 22:29
0

There was actually an async error saving to the database server-side - the above code works. However, after opening the request you do have to set a header if you want to be able to recognize it as xhr. The header you have to set is below, but I updated the code to be the final code I'm working with in my question above:

xml.setRequestHeader("X-Requested-With","XMLHttpRequest")
cadlac
  • 2,802
  • 3
  • 18
  • 34