2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【LWC】LEXで添付ファイル(Attachment)を利用したい場合に。

Posted at

LEXで添付ファイルを使いたい

Classic時代からSalesforceを利用している場合、LEX移行時にファイルの取り扱いが課題になったりしますよね。

Salesforce Classic で添付したファイルが Lightning Experience で検索できない
添付ファイルは Lightning Experience で廃止されたため、これは期待された動作です。
添付ファイルは、より頑強な「ファイル」機能により置き換えられました。

もちろんLEXを使えればそれでいいですが、Classicで機能を開発している場合は、スムーズにいかない場合もあるでしょう。

出番は少ないと思いますが、LEXで添付ファイル(Attachment)を利用するためのLWCをご紹介します。

Sample:添付ファイルアップローダ

lwc_attachment.png

主な機能は下記のとおりです。

  1. 添付ファイル(Attachment)のアップロード
  2. 添付ファイル(Attachment)の一覧表示(プレビューあり)
  3. 添付ファイル(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への移行が進むといいですね!

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?