0

I am uploading multiple file(s) using a file reader

My aim is to get the base64 data of every files as array and output to console. But my code is always displaying empty array due to async

How can I display the base64 array when all filereaders are completely read?

My code is here

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
            <script>
    var file;
    var allfiles = [];

    function uploadForm() {
        Object.keys($('#file')[0].files).forEach(function(f){
          reader = new FileReader()
          console.log("---------")
          reader.readAsDataURL( $('#file')[0].files[f]);
          reader.onloadend = function(e) {
              allfiles.push(e.target.result);
              showMessage("Uploaded")
          };
        });
        console.log(JSON.stringify(allfiles))
        showMessage('Uploading file..<img width="20px;" src="https://c.tenor.com/XK37GfbV0g8AAAAi/loading-cargando.gif"/>');
    }
    
       /* Object.keys(files).forEach(function(f){
          alert(files[f])
          reader.readAsDataURL(files[f]);
        })*/

    function showMessage(e) {
        $('#progress').html(e);
        $('#file').val('');
    }
</script>
    
    
        <table cellpadding="5px">
        <tr>
            <td>Select File:</td>
            <td>
                <input id="file" type="file" value="" accept=".csv,.xlsx,.docx,.rtf,.pdf,.pptx,.txt" multiple>
            </td>
        </tr>
        <tr>
            <td colspan="2"><button onclick="uploadForm(); return false;">Upload</button>&emsp;</td>
        </tr>
        <tr>
            <td colspan="2">
                <div id="progress"></div>
            </td>
        </tr>
    </table>
    

2
  • stackoverflow.com/questions/24843508/… Commented Sep 28, 2021 at 11:35
  • I modified as you suggested, but now I am facing this issue (Question revised) Commented Sep 28, 2021 at 11:44

1 Answer 1

1

In your specific case, readAsDataURL is completing before reader.onloadend gets assigned a listener. Reordering will solve it:

reader.onloadend = function(e) {
    allfiles.push(e.target.result);
    showMessage("Uploaded")
};
reader.readAsDataURL( $('#file')[0].files[f]);

But this will not work for larger files (when readAsDataURL behaves async). I will suggest you start using Promises:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
    var file;
    var allfiles = [];

    function loadFile(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader()
            console.log("---------")
            reader.onerror = reject;
            reader.onload = (e) => resolve(e.target.result);
            reader.readAsDataURL(file);
        })
    }

    function filesToArray(files) {
        const out = [];
        for (let i = 0; i < files.length; ++i) out.push(files[i]);
        return out;
    }

    function uploadForm() {

        const files = filesToArray($('#file')[0].files);
        let uploaded = 0;
        const promises = files.map(async f => {
                const result = await loadFile(f);
                showMessage(`${uploaded ++}/${files.length}`);
                allfiles.push(result);
            });

        showMessage('Uploading file..<img width="20px;" src="https://c.tenor.com/XK37GfbV0g8AAAAi/loading-cargando.gif"/>');
        Promise.all(promises)
            .then(r => {
                console.log(allfiles);
                showMessage('Uploaded');
            })
            .catch(e => showMessage('Failed'));
    }

    function showMessage(e) {
        $('#progress').html(e);
        $('#file').val('');
    }
</script>

<table cellpadding="5px">
    <tr>
        <td>Select File:</td>
        <td>
            <input id="file" type="file" value="" accept=".csv,.xlsx,.docx,.rtf,.pdf,.pptx,.txt" multiple>
        </td>
    </tr>
    <tr>
        <td colspan="2"><button onclick="uploadForm(); return false;">Upload</button>&emsp;</td>
    </tr>
    <tr>
        <td colspan="2">
            <div id="progress"></div>
        </td>
    </tr>
</table>

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.