LWCでレコード作成画面を作る【Salesforce】

yellow bokeh photo Lightning Web Component
Photo by rovenimages.com on Pexels.com

私は主に以下の用途で LWC を使ったレコード作成画面を使います。

  • レコード詳細画面から親レコードを作成したい
  • リッチなレコード作成画面が欲しい
    • 標準画面に近いレイアウトで祖父母レコードの値を初期値設定
    • 複数選択リストへの初期値設定
    • ある項目を入力したとき、他項目の値を自動変更(JavaScript を使った画面作成

上記のようにユーザの希望を叶えやすいので、何かと作る機会は多いです。

今回は基本的な作成方法と私が使うテクニックをまとめてみました。

実装例

実装例として、ケースから取引先責任者(親レコード)を作る画面を作ってみました。

<template>
    <template if:false={hasMessage}>
        <lightning-record-edit-form object-api-name="Contact" onsuccess={handleSuccess} onsubmit={handleSubmit} onerror={handleError}>
            <lightning-quick-action-panel header="新規取引先責任者">
                <c-record-error-message if:true={hasContact} message="既にケースに紐づく取引先責任者が存在しています。"></c-record-error-message>
                <h3 class="slds-section__title slds-theme_shade">
                    <span class="slds-truncate slds-p-horizontal_small" title="Section Title">取引先責任者情報</span>
                </h3>
                <div class="slds-grid">
                    <div class="slds-col slds-size_1-of-2 slds-p-horizontal_small">
                        <lightning-input-field field-name="LastName" variant="standard"> </lightning-input-field>
                        <lightning-input-field field-name="FirstName" variant="standard"> </lightning-input-field>
                    </div>
                    <div class="slds-col slds-size_1-of-2 slds-p-horizontal_small">
                        <lightning-input-field field-name="Phone" value={phone} variant="standard"></lightning-input-field>
                        <lightning-input-field field-name="Email" value={email} variant="standard"> </lightning-input-field>
                    </div>
                </div>
                <h3 class="slds-section__title slds-theme_shade slds-m-top_small">
                    <span class="slds-truncate slds-p-horizontal_small" title="Section Title">詳細情報</span>
                </h3>
                <div class="slds-grid">
                    <div class="slds-col slds-size_1-of-1 slds-p-horizontal_small">
                        <lightning-input-field field-name="Description" variant="standard"> </lightning-input-field>
                    </div>
                </div>
                <div slot="footer">
                    <lightning-button variant="neutral" label="キャンセル" onclick={closeModal}></lightning-button>
                    <lightning-button variant="brand" label="保存" class="slds-m-left_x-small" type="submit" disabled={disabled}></lightning-button>
                </div>
            </lightning-quick-action-panel>
        </lightning-record-edit-form>
    </template>
    <c-record-success-message if:true={hasMessage} obj-name='取引先責任者' record-id={createdRecordId} record-name={createdRecordName}></c-record-success-message>
</template>
import { LightningElement, api, wire } from 'lwc';
import { CloseActionScreenEvent } from 'lightning/actions';
import { getRecord, getFieldValue, updateRecord } from 'lightning/uiRecordApi';
import SUPPLIED_PHONE_FIELD from '@salesforce/schema/Case.SuppliedPhone';
import SUPPLIED_EMAIL_FIELD from '@salesforce/schema/Case.SuppliedEmail';
import CONTACT_ID_FIELD from '@salesforce/schema/Case.ContactId';

const FIELDS = [
    SUPPLIED_PHONE_FIELD,
    SUPPLIED_EMAIL_FIELD,
    CONTACT_ID_FIELD
];

export default class CreateContactFromCase extends LightningElement {
    @api recordId;

    @wire(getRecord, { recordId: '$recordId', fields: FIELDS })
    case;

    get phone() { return getFieldValue(this.case.data, SUPPLIED_PHONE_FIELD); }
    get email() { return getFieldValue(this.case.data, SUPPLIED_EMAIL_FIELD); }

    get hasContact() {
        const contactId = getFieldValue(this.case.data, CONTACT_ID_FIELD);
        return contactId != null;
    }
    get disabled() {
        return this.hasContact || this.isSaving;
    }

    isSaving = false;
    handleSubmit(event) {
        this.isSaving = true;
    }

    handleError(event){
        this.isSaving = false;
    }

    hasMessage = false;
    createdRecordId;
    createdRecordName;

    handleSuccess(event) {
        // ケースの親として作成した取引先責任者を設定
        this.createdRecordId = event.detail.id;
        this.createdRecordName = event.detail.fields.LastName.value + event.detail.fields.FirstName.value;
        const fields = {
            "Id": this.recordId,
            "ContactId": this.createdRecordId
        };
        const recordInput = { fields };
        updateRecord(recordInput).then(() => {
            this.hasMessage = true;
        });
    }

    closeModal() {
        this.dispatchEvent(new CloseActionScreenEvent());
    }
}

lightning-record-edit-form を使用する

レコード作成画面を作る際は、lightning-record-edit-form を使います。

lightning-record-edit-form の中に、lightning-input-field で項目を並べていくだけでそれっぽいレコード作成画面ができます。

これを基本に、やりたいことに合わせて機能を付け足していきます。

初期値の設定について

JavaScript 側の設定

実装例のこの辺の部分で、詳細ページを開いているレコード(今回はケース)から値を取得しています。
今回の例ではケースの Web メール と Web 電話 をそれぞれ取引先責任者のメールと電話の初期値として設定するようにしています。

    // このように書いておけば、開いているページのレコードの ID が recordId に入る
    @api recordId;

    // getRecord でレコードの項目値を取得。結果はその後に書いた変数 (case) に入る
    @wire(getRecord, { recordId: '$recordId', fields: FIELDS })
    case;

    // get メソッド。返される値は html 側で使用できる。
    get phone() { return getFieldValue(this.case.data, SUPPLIED_PHONE_FIELD); }
    get email() { return getFieldValue(this.case.data, SUPPLIED_EMAIL_FIELD); }

HTML 側の設定

lightning-input-field の value={変数} で初期値を指定します。

<lightning-input-field field-name="Phone" value={phone} variant="standard"></lightning-input-field>
<lightning-input-field field-name="Email" value={email} variant="standard"></lightning-input-field>

保存ボタン連打対策

連打でレコードが重複作成されるのを防ぐために、ボタン押下後は非活性にします。

lightning-button において、disabled=ブール値 でボタンの活性/非活性を制御できます。

<lightning-button variant="brand" label="保存" class="slds-m-left_x-small" type="submit" disabled={disabled}></lightning-button>

ボタンが押下されたことは onsubmit, 保存中にエラーが起きた場合は onerror で拾えます。

<lightning-record-edit-form object-api-name="Contact" onsuccess={handleSuccess} onsubmit={handleSubmit} onerror={handleError}>
    get disabled() {
        return this.hasContact || this.isSaving;
    }

    isSaving = false;
    handleSubmit(event) {
        this.isSaving = true;
    }

    handleError(event){
        this.isSaving = false;
    }

レコード作成後の処理

保存後のレコードの値を取得して他のレコードを更新

この辺は以下の記事で書いています。

レコード作成成功画面の表示

保存に成功した場合、成功メッセージを表示します。

<c-record-success-message if:true={hasMessage} obj-name='取引先責任者' record-id={createdRecordId} record-name={createdRecordName}></c-record-success-message>

この部分は他の画面でも使いまわせるようにコンポーネント化しています。

<template>
    <div style="height:4rem">
        <div class="slds-notify_container slds-is-relative">
            <div class="slds-notify slds-notify_toast slds-theme_success" role="status">
                <lightning-icon icon-name="utility:success" alternative-text="Success!" variant="inverse" size="small"
                    title="default style" class="slds-m-right_x-small"></lightning-icon>
                <div class="slds-notify__content">
                    <h2 class="slds-text-heading_small ">
                        {objName} <a href={recordURL}>"{recordLabel}"</a> {message}
                    </h2>
                </div>
            </div>
        </div>
    </div>
</template>
import { LightningElement, api } from 'lwc';

export default class RecordSuccessMessage extends LightningElement {
    @api recordId;
    @api recordName;
    @api objName;
    @api type;

    get recordURL() {
        return '/' + this.recordId;
    }

    get recordLabel() {
        return this.recordName ? this.recordName : this.recordId;
    }

    get message() {
        if (this.type === 'update') {
            return 'が更新されました。';
        } else {
            return 'が作成されました。';
        }
    }
}

コメント

タイトルとURLをコピーしました