2

I'm trying to use the xlsx.js library of cdnjs in a Lightning component. (https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.8.0/xlsx.js). I downloaded the js file and addit as an static resource but in the code when I try to use the XLSX object, always get an "undefined" error.

The resource always has the text/plain MIME Type, so I don't know if the problem is that SF cannot detect that is a java script file.

for the component I'm using the next syntaxis to get the file:

<ltng:require scripts="/resource/JsLibXlsx"
              afterScriptsLoaded="{!c.jsLoaded}"/>

in the controller just for verify the process I have this:

jsLoaded: function(component, event, helper) {
    alert('versión 7');
    try{
        var xls = new XLSX();
        alert(xls);
    }
    catch(ex){
        alert(ex);
    }

}

alert shows

alert error any ideas for this issue?

Thanks.

3 Answers 3

4

So, to make your XSLX library work, several things need to be done:

  1. Download XLSX.js - full library is more preferable, since you'll need to modify sources a bit.
  2. Open XLSX.js and right after the line

    var XLSX = {};

    (for me it was 5th line), add this line of code:

    window.XLSX = XLSX;

  3. Load modified library file as a static resource and reference it in your component as you would do with any other js library:

    <ltng:require scripts="{!$Resource.XLSX"}/>

  4. Library variable will be available in controller methods as XLSX. E.g.

    readFile: function (component, event) {
        var file = event.getSource().get("v.files")[0];
        var reader = new FileReader();
        reader.onloadend = function(e) {
            XLSX.read(e.target.result);
        };
        reader.readAsArrayBuffer(file);
    }
    

Explanation: by default, XLSX library inside the XLSX.js file is simply referenced as:

var XLSX = {};

In ordinary js this would be considered as a global variable, but lightning locker service encloses each library in a Proxy object, so that the library lives in it's own context. However, proxy object leaves direct references to window global context, if there were any. We simply explicitly order locker service to leave a reference to XLSX object in global window context for us.

Source: experience.

Additions: standard XLSX.js library doesn't include gzip library. So if you are not going to add it separately, you should modify and use xlsx.full.min.js. Basically, you should do the same thing as was described before, but for minified version of the library.

2
  • This is the right solution. xlsx library is not yet Locker service compatible as suggested by @sfdcfox. What needs to be done is modify xlsx.js as suggested by Alex Fisher and you would also find jszip.js also in the same dist folder where you have xlsx.js. Add that also like below and then it would work like a charm. Thanks to Alex Fisher <ltng:require scripts='/resource/jszip,/resource/XLSX_To_JSON' afterScriptsLoaded="{!c.scriptsLoadedHandler}" /> Mar 31, 2019 at 18:59
  • <ltng:require scripts='/resource/jszip,/resource/XLSX_To_JSON' afterScriptsLoaded="{!c.scriptsLoadedHandler}" /> Mar 31, 2019 at 19:01
3

First, make sure you're using the $Resource value provider. Second, make sure that your Static Resource is using the text/javascript mime type. Not all browsers support using text/plain files as JavaScript, since this is a potential security issue. Third, check your console for any load errors (press F12 to view the console). It's possible that XLSXJS might simply not be compatible with Lightning Locker Service at this time.

3
  • hi @sfdcfox. in F12 console there are no 404 or javascript errors but the one that I showed in the question. In fact in the mime type we have test/palin, but in the configuration I have no option to change it to test/javascript. I already try to copy all the text of the js library and paste it in a new static resource from developer console (where I can use the right mime type) but it keeps saving and never ends this process. Just for the record... the library works fine in a visualforce page. Jul 28, 2017 at 20:42
  • 1
    if anyone needs this information, after a long research, I saw that the problem is that SF doesn't use the file as a js library but a text file. if I use $Resource I get the next error on browser console: Refused to connect to 'ccrenew--zagadevsb.cs43.my.salesforce.com/one/…' because it violates the following Content Security Policy directive: "connect-src 'self' api.bluetail.salesforce.com preprod.bluetail.salesforce.com cs43.salesforce.com staging.bluetail.salesforce.com *.cs43.visual.force.com". As I see the library is not compatible Jul 28, 2017 at 22:55
  • @PiojoNieto Did you found any other solution to read xlsx file in lightning component? Dec 1, 2017 at 9:02
0

As displayed in answers before you need to use xlsx library. Upload the file as a static resource and import that into your component.

In my case I needed to use the xlsx.full.min.js which is the version that works alone. As all the xlsx.full.min.js files I found were encrypted I couldn't do one of the prerequisites needed which is adding to the xlsx.full.min.js the following lines "window.XLSX = XLSX;" . LWC needs this line to assign the correct context to the library.

What I did was adding window.xlsx to each call I did in my code to the library. In my case I implemented it in LWC but it should be the same in aura. Here is an example of the function that reads the xls.

import { LightningElement,track,wire } from 'lwc';

import { loadScript } from 'lightning/platformResourceLoader'; import XLSX from '@salesforce/resourceUrl/xlsx';

export default class importxls extends LightningElement { @track xlsxLoaded = false; @track errorMessage = '';

connectedCallback() {
    loadScript(this, XLSX)
        .then(() => {
            this.xlsxLoaded = true;
        })
        .catch(error => {
            console.error('Error loading xlsx.js file: ', error);
        });
}

handleFileUpload(event) {
    // Get the uploaded file
    const uploadedFile = event.target.files[0];
    const fileType = uploadedFile.name.split('.').pop();
    if(fileType === 'xls' || fileType === 'xlsx'){
        // Clear the error message
        this.errorMessage = '';
        // Read the contents of the file
        const reader = new FileReader();
        reader.onload = (e) => {
            // Get the binary data
            const binaryData = e.target.result;
            // Convert the binary data to a JavaScript object
            try{
              if(this.xlsxLoaded) {
                const workbook = window.XLSX.read(binaryData, { type: 'binary' });
                const firstSheetName = workbook.SheetNames[0];
                const worksheet = workbook.Sheets[firstSheetName];
                // Use the sheet_to_json method to convert the worksheet to a JavaScript object
                const jsonData = window.XLSX.utils.sheet_to_json(worksheet);
                console.log(jsonData);
              }
            }
            catch(error){
                console.log(error);
            }
            // Now you can use the jsonData to display the data in your LWC.
        }
        reader.readAsBinaryString(uploadedFile);
    }else{
        this.errorMessage = 'Invalid file type';
    }
}

}

Note that this is a LWC code. The key concept is to use the context directly on your js file. Like this:enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .