Lightning Web ComponentsでCSVファイルを出力する

前回は、Lightning Web ComponentsでCSVファイルをインポートする方法についてご紹介しました。

今回はその逆のCSVファイルを出力する方法についてご紹介します。

前提

  • 取引先の名称と都道府県を出力します。
  • 出力されるCSVファイルはShift-JISです(まだ、UTF-8のCSVファイルを扱えるソフトウェアは少ないため)
  • 以下の外部ライブラリを使います。
  • こんなUIにします。

作ってみましょう

htmlファイル

Lightning Web Componentsらしいヘッダと、データテーブルで取引先情報を表示します。

<template>
        <!-- PAGE HEADER -->
        <div class="slds-page-header" role="banner">
            <div class="slds-grid">
                <div class="slds-col slds-has-flexi-truncate">
                    <!-- HEADING AREA -->
                    <p class="slds-text-title_caps slds-line-height_reset">サンプル</p>
                    <h1 class="slds-page-header__title slds-truncate" title="取引先エクスポート">取引先エクスポート</h1>
                    <!-- / HEADING AREA -->
                </div>
                <div class="slds-col slds-no-flex slds-grid slds-align-top">
                    <lightning-button label="エクスポート" onclick={handleExportClick}></lightning-button>
                </div>
            </div>
        </div>
        <div class="slds-grid slds-gutters">
            <div class="slds-col">
                <lightning-datatable
                    key-field="Id"
                    data={record}
                    columns={columns}>
                </lightning-datatable>
            </div>
        </div>
    </template>

jsファイル

外部ライブラリを使う、Shift-JISでCSVファイルを出力すると言うところがポイントです。

まずは外部ライブラリの使い方です。

ダウンロードしたライブラリ(jsファイル)を静的リソースに登録します。ここでは、encodingとfilesaverと言う名称で登録しました。

これを、Lightning Web Componentsで使うには、静的リソースをインポートします。インポートした名称は分かりやすくあえて大文字にしています。

import ENCODING from '@salesforce/resourceUrl/encoding';
import FILESAVER from '@salesforce/resourceUrl/filesaver';

インポートすれば使えるかと思いきや、そういうことではなくロードする必要があります。Lightning Web Componentsが生成されるときに呼び出されるconnectedCallback当たりでロードします。

connectedCallback() {
    // Javascriptライブラリをロードする
    Promise.all([
        loadScript(this, ENCODING),
        loadScript(this, FILESAVER)
    ]);
}

ここで押さえて置くポイントがあります。loadScriptした結果、何がロードされたのかと言うことです。

まず、encoding.jsは、Encodingがグローバル定義されていますので、Encodingがロードされます。

次に、FileSaverは、saveAsがグローバル定義されていますので、saveAsがロードされます。

この後、この2つのライブラリを使っていきますが、使うのはEncodingとsaveAsになります(この理解はかなり重要です)

CSVデータを作成します。出力するものを1つの文字列として連結するだけです。

        // 改行
        const crlf = '\r\n';
        // デリミタ文字
        const delimiter = ',';
        // ダブルクォーテーション
        const dq = '\"';
        
        // CSV形式の文字列を作成する
        let csvdata = '';
        for(let i=0 ; i<this.record.length ; i++) {
            csvdata += dq + this.record[i].Name + dq;
            csvdata += delimiter;
            csvdata += dq + this.record[i].BillingState + dq;
            csvdata += crlf;
        }

これで、UTF-8のCSVデータができました。UTF-8でよければFileSaverで出力するだけです。

今回は、Shift-JISで出力しますので、UTF-8をShift-JISに変換する必要があります。encoding.jsライブラリを使って変換します。Encoding.convertが変換しているところです。encoding.jsをロードするとEncodingがロードされるので、Encoding.convertです。

        // CSVデータをShiftJISに変換する
        const unicodeList = [];
        for(let i=0 ; i<csvdata.length ; i++) {
            unicodeList.push(csvdata.charCodeAt(i));
        }
        const shiftjisList = Encoding.convert(unicodeList, 'sjis', 'unicode');
        const uInt8List = new Uint8Array(shiftjisList);

最後にFileSaverライブラリを使って、ファイルを出力します。

通常、CSVファイルのMIMEタイプは、text/csvです。しかし、SalesforceのLockerサービスでは、text/csvの利用を認めていません。

認めているのは、 https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/security_js_mime.htm に掲載されているものだけです。

ですので、text/plainを使います。

あと、FileSaverライブラリをロードするとsaveAsがロードされます。使うのは、saveAsになりますので、注意してください。

// ダウンロードするデータを作成する
        // MIMEタイプはtext/csvを指定するのが普通だが、Salesforce Lockerサービスではサポートしていないためtext/plainを指定
        // https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/security_js_mime.htm
        const downloadData = new Blob([uInt8List], { type: 'text/plain' });

        // ファイルをダウンロードする
        saveAs(downloadData, `Accounts.csv`);

これで、Accounts.csvと言うファイルがShift-JISでダウンロードできます。

jsファイルの全体は以下の通りです。

import { LightningElement, track, wire } from 'lwc';
import { loadScript } from 'lightning/platformResourceLoader';
import ENCODING from '@salesforce/resourceUrl/encoding';
import FILESAVER from '@salesforce/resourceUrl/filesaver';
import getAccounts from '@salesforce/apex/AccountList.getAccounts';

/**
 * データテーブルのカラム定義
 */
const columns = [
    { label: '取引先名', fieldName: 'Name'},
    { label: '都道府県', fieldName: 'BillingState'}
];

export default class ExportAccountToCsv extends LightningElement {
    /**
     * 取引先情報
     */
    @wire(getAccounts)
    wiredGetAccounts({error, data}) {
        if (data) {
            this.record = data;
        } else {
            this.record = undefined;
        }
    }

    @track
    record;

    /**
     * データテーブルのカラム定義
     */
    @track
    columns = columns;

    /**
     * 初期処理
     */
    connectedCallback() {
        // Javascriptライブラリをロードする
        Promise.all([
            loadScript(this, ENCODING),
            loadScript(this, FILESAVER)
        ]);
    }

    /**
     * 表示している取引先をCSVにエクスポートする
     * @param {*} event イベント情報
     */
    handleExportClick(event) {
        // 改行
        const crlf = '\r\n';
        // デリミタ文字
        const delimiter = ',';
        // ダブルクォーテーション
        const dq = '\"';
        
        // CSV形式の文字列を作成する
        let csvdata = '';
        for(let i=0 ; i<this.record.length ; i++) {
            csvdata += dq + this.record[i].Name + dq;
            csvdata += delimiter;
            csvdata += dq + this.record[i].BillingState + dq;
            csvdata += crlf;
        }

        // CSVデータをShiftJISに変換する
        const unicodeList = [];
        for(let i=0 ; i<csvdata.length ; i++) {
            unicodeList.push(csvdata.charCodeAt(i));
        }
        const shiftjisList = Encoding.convert(unicodeList, 'sjis', 'unicode');
        const uInt8List = new Uint8Array(shiftjisList);

        // ダウンロードするデータを作成する
        // MIMEタイプはtext/csvを指定するのが普通だが、Salesforce Lockerサービスではサポートしていないためtext/plainを指定
        // https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/security_js_mime.htm
        const downloadData = new Blob([uInt8List], { type: 'text/plain' });

        // ファイルをダウンロードする
        saveAs(downloadData, `Accounts.csv`);
    }
}