I am trying to upload a file to a Node backend that uses Multer. Multer requires the form to be submitted a specific way. If it's not submitted that way, the request.file parameter will be undefined. I have created an approach that works by using brute force. That working approach looks like this:
index-1.html:
<form method="POST" enctype="multipart/form-data" id="fileUploadForm">
  <input type="file" id="selectedFile" name="selectedFile" /><br/><br/>
  <input type="submit" value="Submit" id="btnSubmit"/>
</form>
...
var btn = document.getElementById('btnSubmit');
btn.addEventListener('click', function(e) {
  e.preventDefault();
  var form = $('#fileUploadForm')[0];
  var data = new FormData(form);
  console.log(data);
  $.ajax({
    type: "POST",
    enctype: 'multipart/form-data',
    url: "/upload",
    data: data,
    processData: false,
    contentType: false,
    cache: false,
    timeout: 600000,
    success: function (data) {
      console.log("SUCCESS!");
    },
    error: function (e) {
      console.log("ERROR : ", e);
    }
  });
});        
The code above successfully posts the file to my server. That server has the following:
server.js
app.post('/upload', upload.single('selectedFile'), function(req, res) {
  if (req.file) {
    console.log('file uploaded');
  } else {
    console.log('no file');
  }
  res.send({});
});
Using the code above, "file uploaded" is displayed in the console window as expected. However, I need a more dynamic approach. For that reason, I need to programmatically build the form in JavaScript. In an attempt to do that, I've created the following:
index-2.html [my UI]
var btn = document.getElementById('btnSubmit');
btn.addEventListener('click', function(e) {
  var form = document.createElement('form');
  form.action = '/upload';
  form.method = 'POST';
  form.enctype = 'multipart/form-data';
  var node = document.createElement("input");                        
  node.name = 'selectedFile';
  node.value = GLOBAL_SELECTED_FILE;
  form.appendChild(node);
  var data = new FormData(form);
  data.append('id', this.id);
  console.log(data);
  $.ajax({
    type: 'POST',
    url: '/profile-picture/upload',
    enctype: 'multipart/form-data',                          
    data: data,                            
    contentType: false,
    processData: false,
    success: function(res) {
      console.log('success!');
    },
    error: function(xhr, status, err) {
      console.log('error');
    }
  });
});
This second approach does not work. To clarify, the GLOBAL_SELECTED_FILE variable is the data of a file that was selected from an input element. The data is loaded via the FileReader api. That looks like this:
var GLOBAL_SELECTED_FILE = null;
var fileReader = new FileReader();      
fileReader.onload = function(e) {
  GLOBAL_SELECTED_FILE = e.target.result;
}
fileReader.readAsDataURL(fileSelected);  // file selected comes from the onchange event on a <input type="file">..</input> element
Basically, I'm loading a preview of the image. Anyways, when I hit the submit button in the working version (index-1.html), I notice in Fiddler that a different value is sent over the value sent in index-2.html.
With the approach in index-1.html, Fiddler shows something like this in the "TextView" tab:
------WebKitFormBoundary183mBxXxf1HoE4Et
Content-Disposition: form-data; name="selectedFile"; filename="picture.PNG"
Content-Type: image/png
 PNG
However, when I look in the "TextView" tab in Fiddler for the data sent via index-2.html, I see the following:
------WebKitFormBoundary9UHBP02of1OI5Zb6
Content-Disposition: form-data; name="selectedFile"
data:image/png;base64,iVBORw0KGg[A LOT MORE TO GO]
It's like the FormData is using two different encodings for the same value. Yet, I don't understand why. How do I get index-2.html to send the image in the same format as index-1.html so that Multer will populate the req.file property?
Thank you!
 
    