1

I am using xlsx.core.min.js to upload excel files to SP and pass their contents to a new list. I have it working in Edge but it will not work in IE 11.

The first console error I received was "Object doesn't support property or method 'charCodeAt'"

I read about the compatibility issues with .readAsArrayBuffer() and replaced it. Then I started receiving the error "Object doesn't support property or method 'readAsBinaryString'"

**note: using only .readAsArrayBuffer() resulted in the original 'charCodeAt' console error **

How can I get this code working? Thank you in advance!

function ExportToTable() {
            var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.xlsx|.xls)$/;
            /*Checks whether the file is a valid excel file*/
            if (regex.test($("#excelfile").val().toLowerCase())) {
                var xlsxflag = false; 
     /*Flag for checking whether excel is .xls format or .xlsx format*/
            if ($("#excelfile").val().toLowerCase().indexOf(".xlsx") > 0) {
                xlsxflag = true;
            }
            /*Checks whether the browser supports HTML5*/
            if (typeof (FileReader) != "undefined") {
                var reader = new FileReader();
                reader.onload = function (e) {
                    var data = e.target.result;
                    /*Converts the excel data in to object*/
                    if (xlsxflag) {
                        var workbook = XLSX.read(data, { type: 'binary' });
                    }
                    else {
                        var workbook = XLS.read(data, { type: 'binary' });
                    }
                    /*Gets all the sheetnames of excel in to a variable*/
                    var sheet_name_list = workbook.SheetNames;

                    var cnt = 0; /*This is used for restricting the script to consider only first sheet of excel*/
                    sheet_name_list.forEach(function (y) { /*Iterate through all sheets*/
                        /*Convert the cell value to Json*/
                        if (xlsxflag) {
                            var exceljson = XLSX.utils.sheet_to_json(workbook.Sheets[y]);
                        }
                        else {
                            var exceljson = XLS.utils.sheet_to_row_object_array(workbook.Sheets[y]);
                        }
                        //alert (exceljson.length + " ----" + cnt);
                        if (exceljson.length > 0 && cnt == 0) {
                            BindTable(exceljson, '#exceltable');
                            cnt++;
                        }
                    });
                    $('#exceltable').show();
                }
                if (xlsxflag) {/*If excel file is .xlsx extension than creates a Array Buffer from excel*/
                    reader.readAsArrayBuffer($("#excelfile")[0].files[0]);
                }
                else {
                    reader.readAsBinaryString($("#excelfile")[0].files[0]);
                }
            }
            else {
               // alert("Sorry! Your browser does not support HTML5!");
           }
        }
        else {
           // alert("Please upload a valid Excel file!");
        }

    }
1

Try using readAsDataUrl instead of readAsBinaryString. readAsBinaryString was originally in the specification, then removed, and then added back for backward comparability. As a result, it wasn't implemented in IE.

Ref: FileReader.readAsBinaryString()

Now I'm guessing that xlsx.core.min.js isn't going to know what to do with a data url and is expecting binary. So you'll have to do the decoding before doing the XLSX.read or XLS.read, and then pass the decoded binary to whichever read. If I'm wrong, and there is some way to change { type: 'binary' } to something that indicates a type of data url, you should just do that.

But if that's not an option, here's a helper function I used with a similar problem to convert a data url to binary:

/**
 * Convert a base64 encoded data url to binary.
 * @input {string} - either a base 64 encoded string or a base64
 * encoded data url.
 * @mime_type {string} - parsed from the data url if possible, 
 * otherwise this is is used, and defaults to 
 * 'application/octet-stream'
 * @returns {Blob} - the decoded binary.
 */
var dataUri2Blob = function(input, mime_type) {
    var result;

    // if not a data url, assume the input is the bytes and 
    // then mimeType is passed, or hard code the 
    // 'application/octet-stream' (which may not work)
    var bytes = input;
    var mimeType = mime_type || "application/octet-stream";

    // if it looks like a data url, parse the bytes and 
    // mimeType from it
    if(input.match(/^data:[-+\w]+\/[-+\w]+;base64,/i)) {
        bytes = atob(input.split(',')[1]);
        mimeType = input.split(',')[0].
            split(':')[1].
            split(';')[0];
    }

    // create an array buffer and decode the bytes to it
    var buffer = new ArrayBuffer(bytes.length);
    var uia = new Uint8Array(buffer);
    for (var i = 0; i < bytes.length; i++) {
        uia[i] = bytes.charCodeAt(i);
    }

    try {
        // create a data view and instantiate a new Blob
        // by mime type
        var dataView = new DataView(buffer);
        result = new Blob([dataView], {
            type: mimeType
        });
    } catch (e) {
        // Old browser, need to use blob builder, including 
        // all versions of internet explorer
        window.BlobBuilder = window.BlobBuilder ||
            window.WebKitBlobBuilder ||
            window.MozBlobBuilder ||
            window.MSBlobBuilder;

        if (window.BlobBuilder) {
            // if there is a blob builder, append the array 
            // buffer to it and get the contents by mime type.
            var blobBuilder = new BlobBuilder();
            blobBuilder.append(buffer);
            result = blobBuilder.getBlob(mimeType);
        }
    }

    return result;
};

Now to use it, you'd just take pass the data url to it like:

var binary = dataUri2Blob(e.target.result);

You don't need to specify the mime_type because it will be parsed from the data url. And you now pass (binary) into which ever XSL(X).read method.

Ref: Answer to TypeError: Object doesn't support property or method 'charCodeAt'

  • If I use .readAsArrayBuffer I get the console error: Object doesn't support property or method 'charCodeAt' – Torybee Feb 11 at 16:36
  • charCodeAt is coming from xlsx.core.min.js – Torybee Feb 11 at 16:57
  • hmm, would I replace my code with this or add it in as a polyfill? Not sure where to put it in – Torybee Feb 12 at 14:04
  • Yeah, fair enough, I found it confusing too and I couldn't remember the context of where I'd used it so I put in a comment instead of expanding it out in my answer. Anyway, I have managed to where I used it before now, so I'm updating my answer to explain it. – Joe McShea Feb 12 at 15:44
  • Note, after I found my old code, I had to change the first part of my answer too, from readAsArrayBuffer to readAsDataUrl. – Joe McShea Feb 12 at 16:10

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.