0

I have following code that works syncronously. Basically it accept html form and parse it's elements into url string.

SmFaq.DataForm = function (f) { // f is HTML form
    var P = new Array();

    /* parsing array */

    var params = P.join("&");
    return params;
}

It worked nice, but now i need to add input type="file". I made request based on this article: Sending forms with JavaScript (Dealing with binary data) and everything works fine except loading binary data in request body. My function return string before file was readed.

Task: i need to read and add binary data to request body string and then return this string. Is it possible? I don't care if GUI will freeze for loading time.

Here's my code:

SmFaq.DataForm = function (f) { 

    var name = f.querySelector('#created_by'); 
    var email = f.querySelector('#created_by_email'); 
    var question = f.querySelector('#question'); 
    var file = { 
        dom: f.querySelector('#file'), 
        binary: null 
    }; 

    var reader = new FileReader(); // to read binary data 


    if (file.dom.files[0]) { 
        reader.readAsBinaryString(file.dom.files[0]); 
    } 

    file.dom.addEventListener('change', function() { 
    if (reader.readyState === FileReader.LOADING) { 
        reader.abort(); 
    } 

        reader.readAsBinaryString(file.dom.files[0]); 
    }); 

    reader.addEventListener('loadend', function() { 
        file.binary = reader.result; 
        console.log('Binary data loaded!'); 
    }); 

    return sendData(); 

    function sendData() { 

        if (!file.binary && file.dom.files.length > 0) { 
            setTimeout(sendData, 2000); 
            return; 
        } 


        var boundary = "1234567890"; 

        var data = ''; 

        data += '--' + boundary + '\r\n'; 
        data += 'content-disposition: form-data; ' 
        + 'name="' + file.dom.name + '";' 
        + 'filename="' + file.dom.files[0].name + '"\r\n'; 
        data += 'Content-Type: ' + file.dom.files[0].type + '\r\n'; 
        data += '\r\n';
        data += file.binary + '\r\n';

        data += '--' + boundary + '\r\n'; 
        data += 'content-disposition: form-data; name="' + name.name + '"\r\n'; 
        data += '\r\n'; 
        data += name.value + '\r\n'; 

        data += '--' + boundary + '\r\n';
        data += 'content-disposition: form-data; name="' + email.name + '"\r\n'; 
        data += '\r\n'; 
        data += email.value + '\r\n'; 

        data += '--' + boundary + '\r\n';
        data += 'content-disposition: form-data; name="' + question.name + '"\r\n'; 
        data += '\r\n'; 
        data += question.value + '\r\n'; 
        data += '--' + boundary + '--'; 
        data += '\r\n'; 

        return data; 
    }
}

I do not know this async things so it sure not working as expected.

Plese do not use ES7 features, i work with legacy code and have no possibility to use Babel.

2
  • 1
    "Is it possible?" — No. Commented Dec 13, 2017 at 9:27
  • Use formdata instead! if you need a polyfill for that use mine. there is a minified version that you can just include Commented Jan 12, 2018 at 9:31

1 Answer 1

2

I don't think it is possible to do it synchronously. Here is how to do it asynchronously :

var SmFaq = {};

SmFaq.DataForm = function(f, callback) {
  var name = f.querySelector('#created_by'),
    file = f.querySelector('#file'),
    data = '',
    reader = new FileReader();

  reader.addEventListener('loadend', function() {
    console.log('Here are binary datas !');
    data += reader.result;

    callback(data);
  });

  data += 'Created by ';
  data += name.value;
  data += '\n';

  if (file.files[0]) {
    data += file.files[0].name;
    data += '\n';
    data += ' ... ';
    data += '\n';

    console.log('Waiting for binary datas...');
    reader.readAsBinaryString(file.files[0]);
  } else {
    callback(data);
  }
}

function handleData(data) {
  // Do whatever you want to do with data
  console.log(data);
}

document.getElementById('myForm').addEventListener('submit', function(e) {
  e.preventDefault();
  SmFaq.DataForm(this, handleData);
});
<form id="myForm">
  <input type="text" id="created_by" placeholder="Who Am I ?" /><br />
  <input type="file" id="file" /><br />
  <input type="submit" value="Submit" />
</form>

Change the way DataForm is called to add a callback to it, and call the callback function when you have all your datas. Then you handle those datas inside the callback function, handleData in my example.

Sign up to request clarification or add additional context in comments.

Comments

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.