Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 File API: onload too slow

I new to JavaScript an jQuery and Google doesn't lead to an answer. I am writing a online Ebook reader. This is the code for a library where the user can input multiple epub files and relevant information(like Author) should be displayed in a table. To do this I need to extract the ePub file. The jsZip library works perfect. The contents must be displayed in a table which is dynamically created(since I don't know the amount of files).

The problem is that the for loops is to fast and creates all the cells with only the name and filesize within them and after the for loop completes the onload of the FileReader executes and adds all the contents into the very last cell. In this code the alert("A") happens as many times as files that were inputted before alert("B") happens. Is there some way that I can make the loops wait until the onload of the FileReader is done?

function handleFileSelect(evt) {
var files = evt.target.files;
var rows = Math.ceil(files.length/3);
var a = 0;
var root = document.getElementById('mainTable');
var tab=document.createElement('table');
tab.style.textAlign = "center";
var row, cell;
var tbo=document.createElement('tbody');
for(var i  = 0; i != rows; i++)
{
  row=document.createElement('tr');
  for(var j = 0; (j < 3);j++)
  {
   cell = document.createElement('td');
   cell.height = "300px";
   cell.width = "300px"
   if(a <indexes.length)
   {
        var f = files[a];
        var str = f.name;
        str = str.substring(0, str.length - 5);
        str = "File Name: " + str;
        cell.appendChild(document.createTextNode(str));
        cell.appendChild(document.createElement('br'));
        str = "File Size: " + Math.round(f.size/1024) + " KB";
        cell.appendChild(document.createTextNode(str));
        cell.appendChild(document.createElement('br'));
        var reader = new FileReader();
        reader.onload = (function(theFile) 
        {
          return function(e) 
          {
              alert("B");
              var zip = new JSZip(e.target.result);
              $.each(zip.files, function (index, zipEntry) 
              {
                  cell.appendChild(document.createTextNode(zipEntry.name));
                  cell.appendChild(document.createElement('br'));
                  //row.appendChild(cell);
              });
          }
        })(f);
        reader.readAsArrayBuffer(f);
        alert("A");
        a++;
    }
    row.appendChild(cell);
  }
  tbo.appendChild(row);
}
tab.appendChild(tbo);
root.appendChild(tab);              
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
like image 908
Eduan Bekker Avatar asked Apr 03 '13 20:04

Eduan Bekker


1 Answers

Your problem is that the variable cell used within your onload handler will refer to the last value assigned to cell in the outer loop. You can get around this by putting the file processing in a separate function which will create it's own scope.

function read_zip_file(f, cell) {
    var reader = new FileReader();
    reader.onload = (function(theFile) 
    {
      return function(e) 
      {
          alert("B");
          var zip = new JSZip(e.target.result);
          $.each(zip.files, function (index, zipEntry) 
          {
              cell.appendChild(document.createTextNode(zipEntry.name));
              cell.appendChild(document.createElement('br'));
              //row.appendChild(cell);
          });
      }
    })(f);
    reader.readAsArrayBuffer(f);
}

Then within the outer loop you can call:

read_zip_file(f, cell);
like image 97
Ali Gangji Avatar answered Sep 28 '22 09:09

Ali Gangji