LEXで添付ファイルを使いたい
Classic時代からSalesforceを利用している場合、LEX移行時にファイルの取り扱いが課題になったりしますよね。
Salesforce Classic で添付したファイルが Lightning Experience で検索できない
添付ファイルは Lightning Experience で廃止されたため、これは期待された動作です。
添付ファイルは、より頑強な「ファイル」機能により置き換えられました。
もちろんLEXを使えればそれでいいですが、Classicで機能を開発している場合は、スムーズにいかない場合もあるでしょう。
出番は少ないと思いますが、LEXで添付ファイル(Attachment)を利用するためのLWCをご紹介します。
Sample:添付ファイルアップローダ
主な機能は下記のとおりです。
- 添付ファイル(Attachment)のアップロード
- 添付ファイル(Attachment)の一覧表示(プレビューあり)
- 添付ファイル(Attachment)の削除
以下、サンプルコードです。
##html
attachmentFileUploader.html
<template>
<lightning-card icon-name="standard:file">
<h1 slot="title"><strong>添付ファイルアップローダ</strong></h1>
<div>
<div style="margin-left:4%; display: inline-block;">
<lightning-input label="" name="file uploader" onchange={handleFilesChange} type="file" multiple></lightning-input>
</div>
<div style="margin-left:1%; display: inline-block;">
<lightning-button class="slds-m-top--medium" label={UploadFile} onclick={handleSave} variant="brand" disabled={Ubtn_isTrue}></lightning-button>
</div>
<div style="margin-left:4%;">
<templaet if:false={fileselected}>
<div class="slds-text-body_small slds-text-color_error">
{fileName}
</div>
</templaet>
<templaet if:true={fileselected}>
<div class="slds-text-body_small slds-text-color_success">
{fileName}
</div>
</templaet>
</div>
</div>
<lightning-card>
<div style="width: auto;">
<div if:true={dataExist}>
<div class="slds-grid slds-gutters">
<div class="slds-col" style="margin-left:4%; display: inline-block;">
<span>
<lightning-button label={buttonLabel}
icon-name="utility:delete"
disabled={Dbtn_isTrue}
variant="destructive"
onclick={deleteAccounts}></lightning-button>
</span>
<span style="margin-left: 1%">選択:
<span style="color:red;">{recordsCount}</span>
</span>
</div>
</div><br/>
<lightning-datatable
data={data}
columns={columns}
key-field="id"
onrowselection={getSelectedRecords}
resize-column-disabled>
</lightning-datatable>
</div>
<div if:false={dataExist}>
<div class="slds-grid slds-gutters">
<div class="slds-col" style="margin-left:4%;">
<span>登録ファイルがありません</span>
</div>
</div><br/>
</div>
</div>
</lightning-card>
</lightning-card>
</template>
##JavaScript
attachmentFileUploader.js
import { LightningElement, track, api } from 'lwc';
import {ShowToastEvent} from 'lightning/platformShowToastEvent';
import attachmentList from '@salesforce/apex/AttachmentController.getAttachmentList';
import delSelectedFiles from '@salesforce/apex/AttachmentController.deleteAttachments';
import saveFile from '@salesforce/apex/AttachmentController.saveFile';
const columns = [
{ label: 'ファイル名', fieldName: 'FilePreview', type: 'url',
typeAttributes: { label: { fieldName: 'Name' }, tooltip: { fieldName: 'Name' } } },
{ label: '作成日', fieldName: 'CreatedDate', type: 'date',
typeAttributes: { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' } },
// { label: '最終更新日', fieldName: 'LastModifiedDate', type: 'date',
// typeAttributes: { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' } },
{ label: '所有者', fieldName: 'OwnerName'}
];
export default class AttachmentFileUploader extends LightningElement {
@api recordId; // 表示画面レコードID
@track data; // 取得したAttachmentデータをHTMLに渡す
@track columns = columns; // lightning-datatableに割当
@track fileselected=false; // アップロード時のメッセージ表記制御
@track recordsCount = 0; // 選択レコード数
@track buttonLabel = '選択ファイルの削除'; // 削除ボタンラベル
@track UploadFile = 'アップロード実行'; // アップロードボタンラベル
@track dataExist = false;
@track Ubtn_isTrue = false; // uploadボタンのdisabled制御
@track Dbtn_isTrue = true; // deleteボタンのdisabled制御
@track fileName = '';
selectedRecords;
filesUploaded = [];
file;
fileContents;
fileReader;
content;
MAX_FILE_SIZE = 1500000; //ファイルサイズ制限
/********************** 一覧表示処理 **********************/
//画面表示時リスト
connectedCallback() {
this.getAttachments();
}
//Attachment情報取得
getAttachments() {
attachmentList({ parentId: this.recordId })
.then(data => {
console.log('data.forEach前');
data.forEach(a =>{
console.log('a.Owner.Name:'+ a.Owner.Name);
a.FilePreview = '/lightning/r/' + a.Id + '/view';
a.OwnerName = a.Owner.Name;
});
console.log('★data:' + JSON.stringify(data));
this.data = data;
if( this.data.length > 0 ){
this.dataExist = true;
}else{
this.dataExist = false;
}
})
.catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error - getAttachments()',
message: 'データ取得中にエラーが発生しました',
variant: 'error',
}),
);
});
}
/********************** ファイルアップロード処理 **********************/
//アップロードファイルの情報獲得
handleFilesChange(event) {
if(event.target.files.length > 0) {
this.filesUploaded = event.target.files;
this.fileName = event.target.files[0].name;
}
this.Ubtn_isTrue = false;
this.fileselected = false; //表示メッセージ色変更(赤)
this.UploadFile = 'アップロード実行';
}
//アップロード実行ボタン押下時処理
handleSave() {
if(this.filesUploaded.length > 0) {
this.UploadFile = 'Processing....';
this.Ubtn_isTrue = true;
this.uploadHelper();
}
else {
this.fileName = 'アップロードするファイルを指定してください';
this.fileselected = false; //表示メッセージ色変更(赤)
}
}
//サイズ判定&登録データ生成
uploadHelper() {
this.file = this.filesUploaded[0];
if (this.file.size > this.MAX_FILE_SIZE) {
window.console.log('ファイルサイズが大きすぎます');
this.fileName = 'ファイルサイズが大きすぎます(最大'+MAX_FILE_SIZE+'byte)';
return ;
}
this.fileReader= new FileReader();
this.fileReader.onloadend = (() => {
this.fileContents = this.fileReader.result;
let base64 = 'base64,';
this.content = this.fileContents.indexOf(base64) + base64.length;
this.fileContents = this.fileContents.substring(this.content);
this.saveToFile();
});
this.fileReader.readAsDataURL(this.file); //アップロード後画面描画
}
//Apex save処理
saveToFile() {
saveFile({ idParent: this.recordId, strFileName: this.file.name, base64Data: encodeURIComponent(this.fileContents)})
.then(result => {
window.console.log('result ====> ' +result);
this.fileName = this.fileName + ' - アップロード成功';
this.UploadFile = 'アップロード完了';
this.fileselected = true; //表示メッセージ色変更(緑)
this.getAttachments(); //リスト更新
this.dispatchEvent(
new ShowToastEvent({
title: 'Success - saveToFile()',
message: this.file.name + ' - ファイルアップロード処理が成功しました',
variant: 'success',
}),
);
})
.catch(error => {
window.console.log(error);
this.dispatchEvent(
new ShowToastEvent({
title: 'Error - saveToFile()',
message: 'ファイルアップロード中にエラーが発生しました',
//message: error.message,
variant: 'error',
}),
);
});
}
/********************** ファイル削除処理 **********************/
// ファイル情報獲得&選択レコード合計&ボタンdisable制御
getSelectedRecords(event) {
const selectedRows = event.detail.selectedRows;
this.recordsCount = event.detail.selectedRows.length;
let conIds = new Set();
this.buttonLabel = '選択ファイルの削除';
for (let i = 0; i < selectedRows.length; i++) {
conIds.add(selectedRows[i].Id);
}
this.selectedRecords = Array.from(conIds);
window.console.log('selectedRecords ====> ' +this.selectedRecords);
if( this.recordsCount > 0 ){
this.Dbtn_isTrue = false;
}else{
this.Dbtn_isTrue = true;
}
}
//ファイル削除実行ボタン押下時処理
deleteAccounts() {
if (this.selectedRecords) {
this.buttonLabel = 'Processing....';
this.Dbtn_isTrue = true;
this.deleteAttachments();
}
}
//Apex delete処理
deleteAttachments() {
delSelectedFiles({ lstConIds: this.selectedRecords })
.then(result => {
window.console.log('result ====> ' + result);
this.buttonLabel = '選択ファイルの削除完了';
this.getAttachments(); //リフレッシュ
this.dispatchEvent(
new ShowToastEvent({
title: 'Success - deleteAttachments()',
message: this.recordsCount + 'ファイルを削除しました',
variant: 'success'
}),
);
this.template.querySelector('lightning-datatable').selectedRows = [];
this.recordsCount = 0;
})
.catch(error => {
window.console.log(error);
this.dispatchEvent(
new ShowToastEvent({
title: 'Error - deleteAttachments()',
message: 'ファイル削除中にエラーが発生しました',
variant: 'error'
}),
);
});
}
}
attachmentFileUploader.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__RecordPage</target>
<!-- <target>lightning__AppPage</target> -->
<!-- <target>lightning__HomePage</target> -->
</targets>
</LightningComponentBundle>
##Apex
AttachmentController.cls
public with sharing class AttachmentController {
private AttachmentController(){
}
@AuraEnabled
public static list<attachment> getAttachmentList(Id parentId){
return [
SELECT
Id,
Name,
ContentType,
OwnerId,
Owner.Name,
CreatedDate,
CreatedById,
LastModifiedDate,
LastModifiedById
FROM
Attachment
WHERE
ParentId = :parentId AND
IsDeleted = false AND
IsPrivate = false
ORDER BY
CreatedDate DESC
];
}
@AuraEnabled
public static Attachment saveFile(Id idParent, String strFileName, String base64Data) {
// Decoding base64Data
base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');
// inserting file
Attachment cv = new Attachment();
cv.ParentId = idParent;
cv.Name = strFileName;
cv.Body = EncodingUtil.base64Decode(base64Data);
Insert cv;
return cv;
}
@AuraEnabled
public static void deleteAttachments(list<Id> lstConIds){
try {
list<Attachment> lstConsToDelete = new list<Attachment>();
System.debug('lstConIds ====> '+ lstConIds);
for(Id idCon : lstConIds) {
lstConsToDelete.add(new Attachment(Id = idCon));
}
if(!lstConsToDelete.isEmpty()) {
delete lstConsToDelete;
}
}
catch(Exception ex) {
throw new AuraHandledException(ex.getMessage());
}
}
}
AttachmentController.cls-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
##最後に
ここでご紹介した方法は、半ば無理やり添付ファイルを使う方法です。
お役に立てば幸いですが、早くLEXへの移行が進むといいですね!