SheetJS / sheetjs

📗 SheetJS Spreadsheet Data Toolkit -- New home https://git.sheetjs.com/SheetJS/sheetjs
https://sheetjs.com/
Apache License 2.0
35.07k stars 8k forks source link

TypeError: Object doesn't support property or method 'charCodeAt' #532

Closed jindovu closed 7 years ago

jindovu commented 7 years ago

EDIT by @SheetJSDev: the recommended ArrayBuffer approach is summarized [in the wiki](https://github.com/SheetJS/js-xlsx/wiki/Reading-XLSX-from-FileReader.readAsArrayBuffer()) h/t @Aymkdn

Hi Everyone, Currently I use xlsx to read content file excel, but I have problem when I read file, The image description error bellow, now I use IE 11 error

Please help me. Tks you so much.

reviewher commented 7 years ago

@jindovu can you share a code sample that shows this? If I had to guess, you are passing a non-string object (like a Uint8Array) but the reader is expecting a binary string.

jindovu commented 7 years ago

Hi reviewher This is my code, I write directive to read content from Excel file and browser chrome and Fifox still working fine but IE not working, Please take a look the code bellow `.directive("fileread", [ function () { return { scope: { opts: '=' }, link: function ($scope, $elm, $attrs) { $elm.on('change', function (changeEvent) { var reader = new FileReader();

                        reader.onload = function (evt) {
                            $scope.$apply(function () {
                                var filePath = $elm.val();
                                if (filePath.indexOf("csv") >= 0 || filePath.indexOf("xls") >= 0 || filePath.indexOf("xlsx") >= 0) {
                                    var data = evt.target.result;
                                    var workbook = XLSX.read(data, { type: 'binary' });
                                    var dataJson = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
                                    $scope.opts.data = dataJson;
                                }
                            });
                        };

                        var isVersionIe = false || !!document.documentMode;
                        if (isVersionIe) {
                            reader.readAsArrayBuffer(changeEvent.target.files[0]);
                        } else {
                            reader.readAsBinaryString(changeEvent.target.files[0]);
                        }
                    });
                }
            }`
reviewher commented 7 years ago

@jindovu as I suspected, the problem is that you aren't always passing a binary string.

readAsBinaryString will set the result evt.target.result to a binary string, suitable for the binary type. readAsArrayBuffer will return an array buffer and you have to process it. In the demo, the array buffer is converted to a base64 string: https://github.com/SheetJS/js-xlsx/blob/master/index.html#L226-L233 You need something similar.

Do you think it's worth adding an example using angular?

Aymkdn commented 7 years ago

Hi,

I'm not sure your problem is the same, but I guess it's related.

When we try to read a file using readAsArrayBuffer (https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsArrayBuffer) and pass it to XLSX.read with option type:"buffer", then we receive a JavaScript error: Unsupported file undefined (from readSync).

If we pass it to XLSX.read with option type:"binary", then we receive another JavaScript error: TypeError: f.charCodeAt is not a function from firstbyte().

The typical code to read a file would be:

document.getElementById('file-object').addEventListener("change", function(e) {
  var files = e.target.files,file;
  if (!files || files.length == 0) return;
  file = files[0];
  var fileReader = new FileReader();
  fileReader.onload = function (e) {
    var filename = file.name;
    // call 'xlsx' to read the file
    var oFile = XLSX.read(e.target.result, {type: 'binary', cellDates:true, cellStyles:true});
  };
  fileReader.readAsArrayBuffer(file);
});

Example of the problem: http://codepen.io/Aymkdn/pen/YZqdqE

To fix this issue I used http://stackoverflow.com/questions/18582643/alternative-to-readasbinarystring-for-ie10 so I pre-process my file before sending it to XLSX.read:

document.getElementById('file-object').addEventListener("change", function(e) {
  var files = e.target.files,file;
  if (!files || files.length == 0) return;
  file = files[0];
  var fileReader = new FileReader();
  fileReader.onload = function (e) {
    var filename = file.name;
    // pre-process data
    var binary = "";
    var bytes = new Uint8Array(e.target.result);
    var length = bytes.byteLength;
    for (var i = 0; i < length; i++) {
      binary += String.fromCharCode(bytes[i]);
    }
    // call 'xlsx' to read the file
    var oFile = XLSX.read(binary, {type: 'binary', cellDates:true, cellStyles:true});
  };
  fileReader.readAsArrayBuffer(file);
});

Codepen of the fix: http://codepen.io/Aymkdn/pen/aJNPMV

I hope it will help

SheetJSDev commented 7 years ago

@Aymkdn the web demo actually does this conversion. Should this logic be lifted into the read function?

Aymkdn commented 7 years ago

@SheetJSDev yes, it could be into read, but I guess it's also OK to have it as an example into this issue, for later reference for someone else. So it's up to you :-) If you want to add it, let me know and I'll create a pull request.

SheetJSDev commented 7 years ago

@Aymkdn If you have a moment can you add the body of the comment to a page in the project wiki? That way if things change we can modify the recommendation.

Aymkdn commented 7 years ago

@SheetJSDev here you go: https://github.com/SheetJS/js-xlsx/wiki/Reading-XLSX-from-FileReader.readAsArrayBuffer()

victorLessa commented 3 years ago

@Aymkdn Thank you for resolving my problem at the beginning, but do you know if this pre-processing would affect the date format shown in the spreadsheet? Can you tell if it is possible? Because I am finding divergence with the date displayed on the spreadsheet with the date parsed

Aymkdn commented 3 years ago

@VictorLessa > honestly, I don't know… Sorry.