Anderson Anderson - 11 months ago 42
jQuery Question

Combine form fields and user file to send them together as one file

I have a form with input field like some textfields ,textareas,dropdowns and a file upload field which the user will upload while filling the form i want to send form contents (both form field values + uploaded file) as one file to the server below is a very simplified version of my problem .Say i have the following markup

<form id="myForm" method="post" action="something">
<input type="text" name="username" id="username">
<input type="text" name="email" id="email">
<input type="file" name="myFile" id="myFile">

So now what i want is instead of sending above 2 text fields and a file separately i want them to get embedded in a file and then get sent as a whole.

Note that the server where i am sending is third party and only excepts files also file format is proprietary but nonetheless it still a ASCII plain/text.I realize that it's only possible by AJAX and fileReader API so here is what i have tried

var file;
file = this.files[0];
var fr = new FileReader();
fr.onload = function(event){
fileData = fr.result;

e.preventDefault();//prevent submit
var myFile= [$('#username').val(),$('#email').val(),fileData];
url : "some url",
type: "POST",
data: myFile;
success:function(data){ }

Issue is that upon form submission no file gets sent .Any help would be appreciated , thanks.

Update: Tried formData but it still sends variable and files separately

Answer Source

There are 2 parts

  1. Convert file to string format or serialize it on client side using FileReader API
  2. Combine your form values with this string and send them as a file.

Part one

I don't know if you have noticed or not but when you use readAsDataURL() you don't get the original file byte-stream but its base64 encoded version so keeping that in mind change you code to

var fileData;
    file = this.files[0];
    var fr = new FileReader();
    fr.onload = function(event) {
        encfileData = fr.result;
        startInx = encfileData.indexOf('base64');
        startInx += 7;
        tmp = encfileData.substr(startInx);
        //removes the string part "data:text/plain;base64," before decoding

        fileData = atob(tmp); //DECODE

So now you have a string containing your file's byte-stream now as you have said there is some format so depending on that you do whatever manipulation you may need to make it align with the format, since you have mentioned it's plain text format so basic string function are sufficient here.For next part i assume simple colon based CSV format key1:value1,key2:value2

Part Two

Now to truly create a file out of thin air you can use either File or Blob but i would suggest using Blob due to its better support.To contain the file you require FormData simply append your blob to it and send

    var txtData = "\n username:"+$("#username").val()+","+"email:"+$("#email").val();
    // NOTE: windows uses \r\n instead of \n for newlines
    var payLoad =  fileData + txtData;  //append text field data to the file data

    var blob = new Blob([payLoad], {type : 'plain/txt'});
    var form = new FormData();
    var fileName = 'combined.txt';    //filename that will be used on server
    form.append('something', blob, fileName);

        url: "some url",
        type: "POST",
        cache: false,
        contentType: false,
        processData: false,
        data: form,
        success: function(response){alert(response);}

If using php on linux your $_FILES would look like this

    [something] => Array
        [name] => combined.txt
        [type] => plain/txt
        [tmp_name] => /tmp/phpJvSJ94
        [error] => 0
        [size] => 95