2019.10.16

Lightning Webコンポーネントで関連リスト風コンポーネントを作ってみる

  • このエントリーをはてなブックマークに追加
  • follow us in feedly
gettyimages (12409)

概要

Salesforce Spring '19でリリースされたLightning Web Components(LWC)。
リリースから早半年が経ちましたが、みな様は既に使われましたか?
せっかくのTech Blogを書く機会なので、簡単なコンポーネントを作成してみたいと思います。

事前準備

Lightning Web コンポーネントを作為するためのセットアップ等に関しては、下記のブログでも紹介していますので、こちらを参考にしてください。

実践

取引先に関連する取引先責任者の関連リスト風コンポーネントを作成してみたいと思います。
せっかくなので「新規」ボタンから新規の取引先責任者を作成し、リストに追加できるようにしてみました。

関連リスト風コンポーネントイメージ

HTML部分

<template>
    <div style="border: 1px solid #D8D8D8; border-radius: 5px;">
        <article class="slds-card">
            <div class="slds-card__header slds-grid ">
                <header class="slds-media slds-media_center slds-has-flexi-truncate">
                    <div class="slds-media__body">
                        <h2 class="slds-card__header-title">
                            <div class="slds-card__header slds-truncate " title="Contact">
                                <div class="slds-m-left_small slds-m-top_medium">
                                    <lightning-icon icon-name="standard:contact" size="small"></lightning-icon>
                                    <span class="slds-m-left_small" style="font-weight: bold">取引先責任者一覧</span>
                                </div>
                            </div>
                        </h2>
                    </div>
                    <!-- 「新規」ボタン -->
                    <div class="slds-text-align_right slds-m-top_x-small">
                        <lightning-button
                            label="新規"
                            title="新規取引先責任者を作成する"
                            onclick={openModal}
                            class="slds-m-right_x-small">
                        </lightning-button>
                    </div>
                </header>
            </div>
            <div class="slds-scrollable" >
                <!-- 取引先責任者リスト -->
                <lightning-datatable
                    key-field="Id"
                    data={contactList}
                    columns={columns}
                    show-row-number-column
                    hide-checkbox-column>
                </lightning-datatable>
            </div>

        </article>
    </div>

    <!-- 新規取引先責任者ダイアログ -->
    <template if:true={isShowModal}>
        <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <!-- ヘッダー-->
                <header class="slds-modal__header">
                    <button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" title="Close" onclick={closeModal}>
                        <lightning-icon
                            icon-name="utility:close"
                            alternative-text="close"
                            variant="inverse"
                            size="small" >
                        </lightning-icon>
                        <span class="slds-assistive-text">Close</span>
                    </button>
                    <h2 class="slds-text-heading_medium slds-hyphenate">新規取引先責任者</h2>
                </header>
                <!-- 入力部分-->
                <div class="slds-modal__content slds-p-around_medium">
                    <lightning-record-form
                        object-api-name="Contact"
                        fields={createFields}
                        onsuccess={onSuccess}
                        columns="2"
                        oncancel={closeModal}
                        onsubmit={onSubmit}>
                    </lightning-record-form>
                </div>
            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open"></div>
    </template>
</template>
testContactList.html
・LDS
LWCではAuraと同様にLDS(Lightning Design System)を利用することができます。
https://lightningdesignsystem.com/

・lightning-datatable
リスト本体はlightning-datatableを利用しました。
"key-field"はデータのキーになる値。"data"がbodyに該当するもので、"columns"にはヘッダー情報や実データのデータ型、表示方法を渡しています。
詳細はJavaScriptコードをご覧ください。
ヘッダー情報と実データを渡すことで非常に簡単にリストを作ることができました。
その半面できないことや制約も多くあるので、柔軟なリストを作成したい場合はtableタグを利用して地道に作るのがいいかもしれません。
たとえばチェックボックスは設定で1列しか作成することができません。
また、項目にリンクを張ることもできないので、ここでは各取引先責任者オブジェクトの詳細画面に飛ぶリンクを付けることはできません。
(URL単体の項目は作成できます。)

・lightning-record-form
新規作成ダイアログにはlightning-record-formを利用しました。
こちらも表示したい項目情報をJavaScriptでセットすることで入力フォームを作成することができます。
今回は取引先責任者を作成するのでobject-api-name="Contact"にしていますが、カスタムオブジェクトでも同様に作成可能です。
record-id={recordId}を追加することで、指定IDのレコードを編集する画面にもできますが、今回は新規画面ですので意図的に除いています。

JavaScript部分

import { LightningElement, track, wire, api } from 'lwc';
/** トーストメッセージを表示する */
import { ShowToastEvent } from 'lightning/platformShowToastEvent'
import { refreshApex } from '@salesforce/apex';
import getContacts  from '@salesforce/apex/ContactListController.getContactsByAccountId';
/** カスタム表示ラベル:取引先責任者を取得でエラーが発生しました。 */
import ERROR_GETCONTACTS from '@salesforce/label/c.ErrMsg_GetContacts'
/** 新規取引先責任者作成用項目取得 */
import FIELD_LASTNAME from '@salesforce/schema/Contact.LastName';
import FIELD_FIRSTNAME from '@salesforce/schema/Contact.FirstName';
import FIELD_DEPARTMENT from '@salesforce/schema/Contact.Department';
import FIELD_TITLE from '@salesforce/schema/Contact.Title';
import FIELD_PHONE from '@salesforce/schema/Contact.Phone';
import FIELD_EMAIL from '@salesforce/schema/Contact.Email';

export default class TestContactList extends LightningElement {

    // 画面で表示しているレコードID
    @api recordId;
    // 取引先責任者リストヘッダー
    @track columns =  [
        {label:'取引先責任者名', fieldName:'Name' }
        ,{label:'部署', fieldName:'Department'}
        ,{label:'役職', fieldName:'Title' }
        ,{label:'電話', fieldName:'Phone', type:'phone'}
        ,{label:'メール', fieldName:'Email', type: 'email'}
    ];
    // 取引先責任者取得結果
    resultContact = [];
    // 取引先責任者リストデータ
    @track contactList = [];
    // 新規作成モーダルダイアログ表示フラグ
    @track isShowModal = false;
    // 新規ダイアログ表示項目
    createFields = [FIELD_LASTNAME, FIELD_FIRSTNAME, FIELD_DEPARTMENT, FIELD_TITLE, FIELD_PHONE, FIELD_EMAIL];

    /**
     * 取引先責任者取得
     */
    @wire ( getContacts, ( { 'accountId' : '$recordId' } ) )
        setContactList( result ){
            this.resultContact = result;
            if( result.data ){
                this.contactList = result.data;
            }else if( result.error ){
                // トーストでエラー表示
                this.showToast( ERROR_GETCONTACTS, result.error.details.body.message, 'error', 'sticky');
            }
        }

    /**
     * modalダイアログオープン
     */
    openModal(){
        this.isShowModal = true;
    }

    /**
     * modalダイアログクローズ
     */
    closeModal(){
        this.isShowModal = false;
    }

    /**
     * 新規 取引先責任者データ作成実行
     */
    onSubmit( event ){
        // 更新を止める
        event.preventDefault();
        let fields = event.detail.fields;
        // 取引先IDをセット
        fields.AccountId = this.recordId;
        console.log(JSON.stringify(fields));
        // 更新再開
        this.template.querySelector('lightning-record-form').submit(fields);
    }

    /**
     * 新規データ作成成功時メソッド
     * 更新データ画面描画
     */
    onSuccess(event) {

        // 確認用コード
        const contact = event.detail;
        console.log(JSON.stringify(contact));
        const updatedRecord = event.detail.id;
        console.log('onsuccess: ', updatedRecord);
        // @wireのキャッシュをクリアして、取引先責任者データを再取得する。
        refreshApex(this.resultContact);
        //ダイアログクローズ
        this.isShowModal = false;
        //データ作成報告
        this.showToast('SUCCESS','取引先責任者が作成されました。','success','pester');
    }


    /*
     *トーストによるメッセージ表示
     */
    showToast(title,message,varient,mode) {
        const event = new ShowToastEvent({
             title   : title
            ,message : message
            ,variant : varient //info/success/warning/error
            ,mode    : mode    //sticky クローズボタンを押すまで表示
                               //pester 3秒間表示
                               //dismissable sticky+pester
        });
        this.dispatchEvent(event);
    }
}
testContactList.js
・import { ShowToastEvent } from 'lightning/platformShowToastEvent'
 トーストメッセージを表示するためのものです。

・import { refreshApex } from '@salesforce/apex';
 @wireで取得したデータを再取得する際、キャッシュをリフレッシュするために使います。

・import getContacts from '@salesforce/apex/ContactListController.getContactsByAccountId';
 取引先責任者データを取得するApexに接続します。

①取引先責任者データを取得する
 @wireを使ってApexに接続し、取引先責任者データを取得します。
 データが正常に取得できた場合は、@track contactListにデータを収め、エラーの場合はトーストでメッセージを表示します。
 キャッシュリフレッシュ用にresultContactにresultデータを保持しておきます。
 
②新規取引先データを作成する
 lightning-record-formで入力されたデータは「保存」がクリックされると"onsubmit"で指定されたメソッドが呼び出されます。
 このままでは、取引先情報が設定されていないエラーデータになってしまうので、
 event.preventDefault();で一旦登録作業を止め、取引先IDに開いている取引先のIDを設定して、更新を再開させます。
 再開時に"querySelector()"をしていますが、これはLWCでgetElementByXXX()が現状利用できないためです。
 
 登録が成功するとonSuccessメソッドが呼ばれます。
 登録後のデータをリストに表示するため、再度データを取得するのですがその際にrefreshApexを利用します。
 refreshApexを利用することでキャッシュをクリアして再取得し、追加したデータを表示することができます。
 contactListは@trackデコレータがついているため、値が更新されると自動で画面表示が更新されます。

Apex部分

public with sharing class ContactListController {

    @AuraEnabled(cacheable=true)
    public static List<Contact> getContactsByAccountId( Id accountId ){
        //取引先に関連する取引先責任者を取得する
        return [
            SELECT Id, Name, Department, Title ,Phone, Email
            FROM Contact
            WHERE AccountId = :accountId
            ORDER BY CreatedDate
        ];
    }
}
TestContactListController.cls
LWCでapexを利用するためにはメソッドに@AuraEnabledアノテーションが必須となります。
また、データを取得するメソッドには(cacheable=true)も必須です。
そのため、JavaScriptから再取得をする場合は、キャッシュのリフレッシュを行わなくてはなりません。

meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="testContactList">
    <apiVersion>45.0</apiVersion>
    <isExposed>true</isExposed>
    <description>test Contact List</description>
    <targets>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>
testContactList.js-meta.xml
最後にメタデータです。
Lightningレコードページに表示させるため<isExposed>をtrueに変更します。
今回はレコードページに表示する用のコンポーネントなので
<targets>
<target>lightning__RecordPage</target>
</targets>
を追加すれば、Lightningレコードページの編集からこのコンポーネントを追加することができるようになります。

注意

LWCのコンポーネントは、現状Salesforce画面上から削除することができません。
削除が必要な際はVSコードもしくはコマンドでの削除となりますので、不要なコンポーネントをうっかり本番環境に上げてしまわないよう注意しましょう。

おわりに

いかがでしたでしょうか。
こんなの標準の関連リストで十分だよ!という声が聞こえてきそうですがそこはサンプルだと目をつぶっていただいて。。
まだ発表ほやほやで、資料も実績も少ないLWCですが、Auraより非常にとっかかり易い印象でした。
今後さらにアップデートもあるかと思うので、より使いやすくなってくれればいいなと思います。
それでは、よいLightning Web Components生活を!
27 件
     
  • banner
  • banner

関連する記事