さいしょに
こんにちは、タンバリン東京開発チームの岩澤です。
Salesforceが公開しているUI開発フレームワークの中でも比較的新しいLightning Web Componentにふれる機会が多いので、本日はLightning Web ComponentでCSVアップロードコンポーネントを作成してSalesforce標準オブジェクトにデータを追加する方法を書いていこうかと思います。
※ Lightning Web Componentは以降LWCと略します。
※ Salesforceは以降SFと略します。
前提知識としては以下のTrailheadで環境構築、基本的なLWCの扱いは完了しているものとします。
クイックスタート: Lightning Web コンポーネント | Salesforce Trailhead
工程
以下の工程で実装していきます。
- CSVファイルの準備
- アップロード画面のコンポーネントをつくる
- JSでアップロードしたデータを取得
- インポート処理を実行
順番にみていきましょう。
CSVファイルの準備
今回はSFの標準オブジェクトである取引先(Account)への登録を行いますので、対象にする数件の項目に対するCSVファイルを用意しました。
以下、CSVファイルを使用します。
account.csv
取引先名,取引先 部門,都道府県 (請求先),電話,種別
user1,部門1,千葉,080-0000-0000,Customor
user2,部門1,東京,080-1111-1111,Customor
user3,部門1,神奈川,080-2222-2222,Customor
user4,部門1,埼玉,080-3333-3333,Customor
DE環境のデフォルト設定で取引先オブジェクトのページに表示されていた項目になります。
都道府県(請求先)は国などその他の項目がマージされて構成された住所(請求先)オブジェクトの一部でオブジェクトマナージャーなどでは見かけからず、API名が見つけづらいので公式ページを参考にします。
https://help.salesforce.com/articleView?id=000323000&language=ja&type=1&mode=1
また、SFに限った話ではないですがCSVファイルを扱う時は最終行に改行がないことを確認してください。
改行をフィールドと認識してしてフィールドが空となりエラーになります。今回のコードでは改行処理はしていないのであしからず。
アップロード画面のコンポーネントをつくる
クイックスタート: Lightning Web コンポーネント | Salesforce Trailhead
上記を参考にcommand ⌘
+shift ⇧
+p
でSFDX: Create Lightning Web Component
を選択→csvtest
(適当)を入力してEnter
→Enter
でデフォルトのlwcフォルダ配下にコンポーネントの雛形が作成されます。
作成されたコンポーネントのフォルダ配下にcsvtest.html
ファイルがありますのでに以下の修正を加えます。
force-app/main/default/lwc/csvtest/csvtest.html
<template>
<lightning-card
title="CSVアップロード"
icon-name="custom:custom15"
>
<div style="padding: 0 20px;">
<div style="
padding: 10px 0 0 0;
">
<lightning-input
type="file"
name="csv"
label="CSV"
onchange={handleCsvUpload}
accept="text/csv"
></lightning-input>
</div>
<p style="padding: 10px 0 0 0;">{fileName}</p>
<div style="
padding: 20px 0 10px 0;
margin: 0 0 0 -5px;
">
<div
if:true={isLoaded}
class="slds-is-relative"
style="
height: 60px;
margin: 0 0 -10px 0;
"
>
<lightning-spinner alternative-text="Loading..." variant="brand"></lightning-spinner>
</div>
<div if:false={isLoaded}>
<div if:true={isSend}>
<lightning-button
variant="brand"
label="送信"
title="Primary action"
onclick={handleUpload}
class="slds-m-left_x-small">
</lightning-button>
</div>
<div if:false={isSend}>
<lightning-button
variant="brand"
label="送信"
disabled
title="Primary action"
onclick={handleUpload}
class="slds-m-left_x-small">
</lightning-button>
</div>
</div>
</div>
</div>
</lightning-card>
</template>
<lightning-input type="file>
でファイル選択ができるようになります。
ファイルを選択するとif:true={isSend}
になり送信ボタンが押せるようになり、送信ボタンを押すとif:true={isLoaded}
になりロード画面が表示されアップロードが始まります。
これらの変数はJS側で定義しています。
また、CSSはインラインで直接書いていますが、同じディレクトリ内でcsvtest.css
ファイルを作成してCSSを書けばファイルを分けることができます。
続いて、コンポーネントの表示の場所を定義していきます。
今回はホームタブの画面にコンポーネントを表示しますのでcsvtest.js-meta.xml
に以下の修正を加えます。
force-app/main/default/lwc/csvtest/csvtest.js-meta.xml
xml version="1.0" encoding="UTF-8"
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
<targets>
要素でSalesforceのどこに表示するか決めている程度の理解でいったん大丈夫な気がします。
ここまで出来ましたら、いったんデプロイしてみましょう。
VSCodeの左側のディレクトリツリーのforce-app/main/default
の部分を右クリックしてSFDX: Deploy Source to Org
をクリックします。

無事にデプロイが完了しましたら、以下の順序で画面に表示します。
・command ⌘
+shift ⇧
+p
でSFDX: Open Default Org
をクリックしてブラウザ表示
・設定
から編集ページ
を開く

・カスタムコンポーネントをキャンバスにドラッグして保存

以上で設定が反映されホームにアップロード画面が表示されます。
補足:カスタムコンポーネントが表示されなかった場合
編集ページを開いた時にメニューのカスタムにコンポーネントが表示されない場合があります。
原因は私のドメイン
が設定されていないことが原因です。

画面の左下[私のドメイン]をリリース
をクリックしてください。
そうしますと以下のようにドメイン名を設定する画面に遷移しますので、お好みのドメインを入力して使用可能か調べる
ボタンをクリックしまして、問題ないようでしたらドメインの登録
をクリックします。

ちょっとした注意なのですが、この設定したドメインは一度設定すると自分では変更出来ず、変更する場合は問合せする必要があります。
自分の開発環境ならなんでもいいですが、僕の場合は案件のサンドボックス環境のドメインに自分の名前を入れてしまうというミスをしました。。
こちらも開発環境ではあるから問題ないとは言っていただいたのですが、本番環境だとしたら結構しんどいことになってたかと思いますので、実務の場合は一度ドメインは相談して決めるのがいいかと思います。
登録処理をしますと以下のような画面が表示されます。

反映まで少し時間がかかるようです。数分で反映されますのでちょこっと休憩しましょう。
メールでお知らせするとのことですが、メールを確認しなくても少ししますと以下のような画面が表示されますので、ログイン
ボタンをクリックします。
設定したドメインに変更されたトップ画面に遷移されますので、ここまで完了したらカスタムコンポーネントが認識されています。

JSでアップロードしたデータを取得
画面のコーディングは完了しましたので、実際の処理を実装していきます。
SalesForce(以降、SF)側にアップロードする処理自体はApexで行いますので、JS側ではApex側に渡すための選択したアップロードのファイルを取得したり、フロント側のバリデーションの処理などを実装してます。
まずは全体のコードを確認しましょう。以下のフォルダ配下にありますcsvtest.js
に以下の変更を加えてください。
force-app/main/default/lwc/csvtest/csvtest.js
// Lightning Web Componentから @wire, @api をインポート
import { LightningElement, api } from 'lwc';
// ShowToastEvent(ポップアップメッセージ)をインポート
import {ShowToastEvent} from 'lightning/platformShowToastEvent';
// Apex Classの定義
import insertCsvData from "@salesforce/apex/csvUploder.insertCsvData";
export default class CsvUploader extends LightningElement {
// アップロードファイル
@api file = null;
// ファイル名(画面表示用)
@api fileName;
// 送信フラグ
@api isSend = false;
@api isLoaded = false;
// ファイルの中身
data;
// ファイルを選択すると発火
handleCsvUpload(event) {
// 選択したアップロードファイルを取得
this.file = event.detail.files;
// ファイル名を取得
this.fileName = this.file[0].name;
// ファイルが選択されたらボタンをアクティブ化
this.isSend = this.file;
// FileReaderオブジェクトの生成
const fileReader = new FileReader();
// ファイルの読み込みが完了したら実行
fileReader.onloadend = () => {
// 読み込み結果を設定
this.data = fileReader.result;
}
// ファイルを読み込み
fileReader.readAsText(this.file[0]);
}
// csvアップロード処理
handleUpload() {
// アップロードファイルを選択していないと送信させない
if (!this.file) {
return
}
// ローディング表示をtrue
this.isLoaded = true;
Promise.resolve().then(() => {
return new Promise((resolve, reject) => {
// ファイルを改行で分割しフィールドごとに配列で取得
const rows = this.data.split(/\r\n|\n/);
console.log(rows);
// データをjson形式で取得
const outputJson = [];
for(let i=1 ; i<rows.length ; i++) {
const cols = rows[i].split(',');
outputJson.push({
Name: cols[0],
Site: cols[1],
BillingState: cols[2],
Phone: cols[3],
Type: cols[4],
});
}
// Apexでインポート処理
insertCsvData({
jsonData: JSON.stringify(outputJson)
})
.then(result => {
this.data = result;
resolve(this.data);
// 成功ポップアップメッセージ表示
this.dispatchEvent(
new ShowToastEvent({
title: 'Success!!',
message: 'Success!!',
variant: 'success',
}),
);
})
// 失敗ポップアップメッセージ表示
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error!!',
message: error,
variant: 'error',
}),
);
})
});
})
.catch(error => {
console.log(error)
})
// 最終処理
.finally(() => {
// input fileを初期化
this.template.querySelectorAll('lightning-input').forEach(each => {
each.value = "";
});
// アップロードファイルを初期化
this.file = null;
// 送信ボタンを非アクティブ化
this.isLoaded = false;
});
}
}
大体はコメントに処理内容を書いてますので、簡単に説明します。
・ファイル選択をしますとhandleCsvUpload
メソッドが発火します。csvtest.html
の<lightning-input>
にイベントで定義してます。次に以下の処理が実行されます。
- アップロードファイルを取得
- 取得ファイルでfileReaderオブジェクトを生成
- readAsTextでファイルの中身を文字列で取得
・送信ボタンクリックしますとhandleUpload
メソッドが発火します。次に以下の処理が実行されます
- ファイルのデータ内容を改行(レコードごと)で分割し、ループを回す
- カンマ(フィールドごと)で分割、
SFのフィールド名
: フィールドの値
でJson形式の値を取得
- JsonデータをApexへ渡す
インポート処理を実行
インポート処理の前にひとつ確認しておくことがあります。
JSのコードの冒頭にありますimport readCSV from '@salesforce/apex/csvUploder.insertCsvData';
です。
これはApexのcsvUploder
クラスのinsertCsvData
メソッドをreadCSV
で宣言しますという意味です。
ApexとはSalesforceが開発したJavaライクなプログラミング言語になります。
ですので、まだApexクラスもメソッドも作ってないのでファイルを作る必要があります。
command ⌘
+shift ⇧
+p
でSFDX: Create Apex Class
を選択→csvUploder
(適当)を入力してEnter
→Enter
でデフォルトのclassesフォルダ配下にファイルが生成されます。
ファイルが作成されましたらcsvUploder.cls
を以下のように編集してください。
force-app/main/default/classes/csvUploder.cls
public with sharing class csvUploder {
@AuraEnabled
public static void insertCsvData(String jsonData) {
// importデータ格納用変数
List<Account> importData = new List<Account>();
// 引数のデータをリストで取得
List<Object> readData = (List<Object>)JSON.deserializeUntyped(jsonData);
System.debug(readData);
// リストをループ
for(Object o : readData) {
Map<String, Object> m = (Map<String, Object>)o;
// 項目の値を取得
Account a = new Account();
a.Name = (String)m.get('Name');
a.Site = (String)m.get('Site');
a.BillingState= (String)m.get('BillingState');
a.Phone= (String)m.get('Phone');
a.Type = (String)m.get('Type');
importData.add(a);
}
try {
insert importData;
}
catch(DmlException e) {
throw e;
}
}
}
簡単に説明しますと以下の処理を行っています。
- 引数のJsonデータをリストオブジェクトにしてループ
- 対象のフィールド名に対してデータをセット
- インポート処理
以上でコーディングは完了です。
デプロイして実際にCSVファイルをアップロードしてみるとAccount(取引先)にCSVのデータが挿入されていることが確認出来ます。
以上です。