docs.sheetjs.com/docz/docs/03-demos/09-cloud/01-salesforce.md

390 lines
11 KiB
Markdown
Raw Normal View History

2022-06-27 02:05:36 +00:00
---
2022-08-24 00:51:18 +00:00
title: Salesforce LWC
2023-02-28 11:40:44 +00:00
pagination_prev: demos/local/index
pagination_next: demos/extensions/index
2022-06-27 02:05:36 +00:00
---
2023-05-03 03:40:40 +00:00
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
2022-06-27 02:05:36 +00:00
Salesforce apps can use third-party libraries in "Lightning Web Components".
This demo assumes familiarity with Lightning Web Components. Salesforce has a
[detailed introduction.](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.get_started_introduction)
2023-09-24 03:59:48 +00:00
:::caution pass
2022-06-27 02:05:36 +00:00
Salesforce may change the platform in backwards-incompatible ways, so the demo
may require some adjustments. The official documentation should be consulted.
:::
2023-04-09 21:13:24 +00:00
:::note
This demo was last tested on 2023 April 09 using Lightning API version `57.0`.
:::
2022-06-27 02:05:36 +00:00
## Getting Started
This demo was built on a "Developer Edition" account. At the time of writing, an
[account can be created for free.](https://developer.salesforce.com/signup)
### Create Sample Project and Component
2022-08-25 08:22:28 +00:00
<!-- spellchecker-disable -->
2022-06-27 02:05:36 +00:00
Following the steps in ["Develop in Non-Scratch Orgs"](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.get_started_sfdx_deploy):
2022-08-25 08:22:28 +00:00
<!-- spellchecker-enable -->
2022-06-27 02:05:36 +00:00
```bash
## Login
sfdx force:auth:web:login -d -a LWC-Hub
## Create Sample Project and Component
sfdx force:project:create --projectname SheetForce
cd SheetForce
sfdx force:lightning:component:create --type lwc -n sheetComponent -d force-app/main/default/lwc
```
By default, the component will not be available to app pages. A few files must
be changed:
`force-app\main\default\lwc\sheetComponent\sheetComponent.html` add some HTML:
2023-04-09 08:51:51 +00:00
```html title="force-app\main\default\lwc\sheetComponent\sheetComponent.html"
2022-06-27 02:05:36 +00:00
<template>
<!-- highlight-next-line -->
<b>SheetForce demo</b>
</template>
```
`force-app\main\default\lwc\sheetComponent\sheetComponent.js-meta.xml` change
`isExposed` from `false` to `true` and add some metadata:
2023-04-09 08:51:51 +00:00
```xml title="force-app\main\default\lwc\sheetComponent\sheetComponent.js-meta.xml"
2022-06-27 02:05:36 +00:00
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
2023-04-09 08:51:51 +00:00
<apiVersion>57.0</apiVersion>
2022-06-27 02:05:36 +00:00
<!-- highlight-start -->
<isExposed>true</isExposed>
<masterLabel>SheetForce</masterLabel>
<description>SheetJS Demo</description>
<targets>
<target>lightning__AppPage</target>
</targets>
<!-- highlight-end -->
</LightningComponentBundle>
```
### Deploy Sample Project
Deploy the project:
```bash
sfdx force:source:deploy -p force-app -u SALESFORCE@USER.NAME # replace with actual username
```
The custom component can be found in Custom Code > Lightning Components.
![Custom Component](pathname:///files/sfcustcomp.png)
### Initialize App Page
Create an "App Page" in the "Lightning App Builder". Instructions are included
in [Hello World in a Scratch Org](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.get_started_sfdx_hello_world)
The following options should be set:
- The "App Page" option should be selected.
- The App Label should be set to "SheetJS Demo".
- The "One Region" layout should be selected.
Under Custom components, you should see "SheetForce". Click and drag it into
the app builder main view to add it to the page.
2023-04-09 08:51:51 +00:00
Click "Save" then click "Activate". The following options should be set:
2022-06-27 02:05:36 +00:00
- Click "Change..." next to "Icon" and pick a memorable icon
- Under "Lightning Experience" click "LightningBolt" then "Add page to app"
Click "Save" to activate the page, then click the left arrow to return to Setup.
Click the App Launcher and select "Bolt Solutions" then "SheetJS Demo". You
should see a page like
2022-08-25 08:22:28 +00:00
![Demo](pathname:///files/sfinitial.png)
2022-06-27 02:05:36 +00:00
## Adding the Standalone Script
2023-09-22 06:32:55 +00:00
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be downloaded and added as a static resource.
Due to Salesforce name restrictions, the script must be renamed to `sheetjs.js`
2022-06-27 02:05:36 +00:00
2023-05-03 03:40:40 +00:00
<p>1) Download <a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>https://cdn.sheetjs.com/xlsx-{current}/package/dist/xlsx.full.min.js</a></p>
2022-06-27 02:05:36 +00:00
2023-09-19 19:08:29 +00:00
:::warning pass
2022-06-27 02:05:36 +00:00
**DO NOT "COPY AND PASTE"!** The file should be explicitly downloaded. Copying
and pasting corrupts the source code and the component will fail in subtle ways.
The easiest approach is to right-click the link and select "Save Link As..."
:::
2) Move the file to the `force-app/main/default/staticresources/` folder and
rename the file to `sheetjs.js`.
3) Create `force-app/main/default/staticresources/sheetjs.resource-meta.xml`:
2023-04-09 08:51:51 +00:00
```xml title="force-app/main/default/staticresources/sheetjs.resource-meta.xml"
2022-06-27 02:05:36 +00:00
<?xml version="1.0" encoding="UTF-8"?>
<StaticResource xmlns="http://soap.sforce.com/2006/04/metadata">
<cacheControl>Private</cacheControl>
<contentType>application/javascript</contentType>
</StaticResource>
```
4) Deploy the project again:
```bash
sfdx force:source:deploy -p force-app -u SALESFORCE@USER.NAME # replace with actual username
```
2023-09-24 03:59:48 +00:00
:::note pass
2022-06-27 02:05:36 +00:00
The official documentation recommends adding a static resource with a ZIP file.
That approach is not explored in this demo.
:::
Custom Code > Static Resources should now list `sheetjs`:
![Static Resources](pathname:///files/sfstatic.png)
### Test the Static Resource
The script can be loaded from component code with:
```js
2023-03-26 00:55:35 +00:00
import sheetjs from '@salesforce/resourceUrl/sheetjs';
2022-06-27 02:05:36 +00:00
```
The library includes a version number that can be displayed:
1) Add a reference in `sheetComponent.js` and expose the `version` property:
2023-04-09 08:51:51 +00:00
```js title="force-app/main/default/lwc/sheetComponent/sheetComponent.js"
2022-06-27 02:05:36 +00:00
import { LightningElement } from 'lwc';
import { loadScript } from 'lightning/platformResourceLoader';
// highlight-next-line
import sheetjs from '@salesforce/resourceUrl/sheetjs';
export default class SheetComponent extends LightningElement {
version = "???"; // start with ???
async connectedCallback() {
// highlight-next-line
await loadScript(this, sheetjs); // load the library
// At this point, the library is accessible with the `XLSX` variable
this.version = XLSX.version;
}
}
```
2) Reference the variable in `sheetComponent.html`:
2023-04-09 08:51:51 +00:00
```html title="force-app/main/default/lwc/sheetComponent/sheetComponent.html"
2022-06-27 02:05:36 +00:00
<template>
<!-- highlight-next-line -->
<b>SheetForce {version}</b>
</template>
```
3) Deploy the project again and re-load the Bolt Solutions "SheetJS Demo" page:
![Version number](pathname:///files/sfversion.png)
## Exporting Data from SF Lists
2023-09-24 03:59:48 +00:00
:::note pass
2022-06-27 02:05:36 +00:00
There are many different data types and APIs. This demo uses the deprecated
`getListUi` function to pull account data.
:::
### Steps
#### Getting Account Data
The main method to obtain data is `getListUi` and the key for account data is
`ACCOUNT_OBJECT`:
```js
import { getListUi } from 'lightning/uiListApi';
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
// ...
export default class SheetComponent extends LightningElement {
@wire(getListUi, {
objectApiName: ACCOUNT_OBJECT.objectApiName,
listViewApiName: 'AllAccounts'
}) listInfo({ error, data }) {
// LIST DATA AVAILABLE HERE
};
// ...
}
```
#### Generating an Array of Arrays
SheetJS most reliably translates "arrays of arrays", a nested array which
directly maps to individual cell addresses. For example:
```js
var data = [
["Name", "Phone"], // row 1
["Foo Bar", "(555) 555-5555"], // row 2
["Baz Qux", "(555) 555-5556"] // row 3
];
```
The APIs typically return nested objects, so the array must be constructed.
<details><summary><b>Salesforce Representation</b> (click to show)</summary>
The `data` parameter in the callback has a deep structure. Typically one would
set a property in the component and display data in a template:
```js
// ...
// declare records variable in the component
records;
@wire(getListUi, {
objectApiName: ACCOUNT_OBJECT.objectApiName,
listViewApiName: 'AllAccounts'
}) listInfo({ error, data }) {
if (data) {
// data.records.records is the array of interest
this.records = data.records.records;
this.error = undefined;
}
}
// ...
```
The template itself would iterate across the records:
```html
<template>
<template if:true={records}>
<table>
<tr><th>Name</th><th>Phone</th></tr>
<template for:each={records} for:item="record">
<tr key={record.fields.Id.value}>
<td>{record.fields.Name.value}</td>
<td>{record.fields.Phone.value}</td>
</tr>
</template>
</table>
</template>
</template>
```
</details>
A suitable SheetJS array of arrays can be constructed by mapping across records:
```js
var headers = [ "Name", "Phone" ];
this.aoa = [headers].concat(data.records.records.map(record => [
record.fields.Name.value, // Name field
record.fields.Phone.value, // Phone field
]));
```
This is readily exported to a spreadsheet in a callback function:
```js
@api async download() {
await loadScript(this, sheetjs); // load the library
// create workbook
var wb = XLSX.utils.book_new();
var ws = XLSX.utils.aoa_to_sheet(this.aoa);
XLSX.utils.book_append_sheet(wb, ws, "Data");
// export
XLSX.writeFile(wb, "SheetForceExport.xlsx");
};
```
### Complete Example
1) Add a button to `sheetComponent.html` that will call a `download` callback:
2023-04-09 08:51:51 +00:00
```html title="force-app/main/default/lwc/sheetComponent/sheetComponent.html"
2022-06-27 02:05:36 +00:00
<template>
<!-- if the `aoa` property is set, show a button -->
<template if:true={aoa}>
<button onclick={download}><b>Click to Export!</b></button>
</template>
<!-- if the `aoa` property is not set, show a message -->
<template if:false={aoa}><b>Please wait for data to load ...</b></template>
</template>
```
2) Replace `sheetComponent.js` with the following:
2023-04-09 08:51:51 +00:00
```js title="force-app/main/default/lwc/sheetComponent/sheetComponent.js"
2022-06-27 02:05:36 +00:00
import { LightningElement, wire, api } from 'lwc';
import { loadScript } from 'lightning/platformResourceLoader';
import { getListUi } from 'lightning/uiListApi';
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import sheetjs from '@salesforce/resourceUrl/sheetjs';
export default class SheetComponent extends LightningElement {
aoa; // will hold data for export
@wire(getListUi, {
objectApiName: ACCOUNT_OBJECT.objectApiName,
listViewApiName: 'AllAccounts'
}) listInfo({ error, data }) {
if (data) {
var headers = [ "Name", "Phone" ];
// create AOA and assign to `aoa` property
this.aoa = [headers].concat(data.records.records.map(record => [
record.fields.Name.value, // Name field
record.fields.Phone.value, // Phone field
]));
} else if (error) console.log(error);
};
@api async download() {
await loadScript(this, sheetjs); // load the library
// create workbook
var wb = XLSX.utils.book_new();
var ws = XLSX.utils.aoa_to_sheet(this.aoa);
XLSX.utils.book_append_sheet(wb, ws, "Data");
// export
XLSX.writeFile(wb, "SheetForceExport.xlsx");
};
}
```
3) Re-deploy and refresh the app page:
![SF Export Button](pathname:///files/sfexport.png)
The simple export has all of the data:
![Excel Export](pathname:///files/sfxlexport.png)
2023-09-24 03:59:48 +00:00
:::tip pass
2022-06-27 02:05:36 +00:00
[SheetJS Pro](https://sheetjs.com/pro) offers additional styling options like
cell styling, automatic column width calculations, and frozen rows.
2023-03-26 00:55:35 +00:00
:::