2023.09.08

【LWC応用】lightning-datatableとフラット化

Just a moment... (31572)

はじめに

みなさんは、Salesforceのフロントエンド開発でLightning Web Componentsを利用して開発していますか?
Web業界の標準言語(HTML・CSS・JavaScript)を利用するため、Salesforce以外でも使えるスキルが身に付くこともありオススメです。

HTMLを記述する上でSalesforceによって用意されているコンポーネント(<lightning-***>のタグ)を利用しますが、その中でも利用頻度の高い「lightning-datatable」を使う際の小技を紹介したいと思います。

lightning-datatable

lightning-datatable」はSalesforceのテーブルUIを表示するコンポーネントです。
レコードをリストビュー形式で表示することができ、インライン編集することも可能です。
以下のようなケースで利用されることがあります。
・検索画面の結果表示部分
・カスタマイズした関連リスト
・明細の一括編集&保存
例として見積品目の一覧を表示する画面を作成します。
<!-- 見積品目 -->
<lightning-datatable
        key-field="Id"
        data={dataList}
        columns={columnsDefine}
        hide-checkbox-column>
</lightning-datatable>
dataTable.html
HTMLには「lightning-datatable」のコンポーネントを使います。dataは表示するレコードのリスト、columnsは表示する列情報のリストを設定する必要があります。
import { LightningElement, api, wire } from 'lwc';
import getQuoteLine from '@salesforce/apex/dataTableController.getQuoteLine';
export default class DataTable extends LightningElement {
        @api recordId;
        columnsDefine = [
                { label: '商品名', fieldName: 'Product2.Name', type: 'text' },
                { label: '商品コード', fieldName: 'Product2.ProductCode', type: 'text' },
                { label: '商品ファミリ', fieldName: 'Product2.Family', type: 'text' },
                { label: '販売価格', fieldName: 'UnitPrice', type: 'currency' },
                { label: '数量', fieldName: 'Quantity', type: 'number',
                        typeAttributes: { minimumFractionDigits: '2' } },
                { label: '小計', fieldName: 'Subtotal', type: 'currency'}
        ];
        dataList = [];

        // 見積品目の一覧表示
        @wire ( getQuoteLine, ( { quoteId : '$recordId' } ) )
        setQuoteLineItemList( result ) {
                // Apex正常終了の場合
                if ( result.data ) {
                        console.log( 'result.data:' + JSON.stringify( result.data ));
                        this.dataList = result.data;
                // Apex異常終了の場合
                } else if ( result.error ) {
                        console.log( 'result.error:' + JSON.stringify( result.error ));
                }
        }
}
dataTable.js
JavaScriptは「lightning-datatable」に設定するテーブル列情報の定義と見積品目レコードを取得する処理を記述しています。今回は見積品目の項目「販売価格」「数量」「小計」と「商品」の情報を元に商品マスタから「商品名」「商品コード」「商品ファミリ」を表示します。
public with sharing class dataTableController {
        // 見積品目を取得
        @AuraEnabled(cacheable=true)
        public static List<QuoteLineItem> getQuoteLine( String quoteId ) {
                return [
                        SELECT
                                Id,
                                Product2.Name,
                                Product2.ProductCode,
                                Product2.Family,
                                Product2Id,
                                UnitPrice,
                                Quantity,
                                Subtotal
                        FROM
                                QuoteLineItem
                        WHERE
                                QuoteId = :quoteId
                ];
        }
}
dataTableController.cls
ApexはSQOLで見積に紐付く見積品目のレコードを取得する処理を記述します。画面に表示予定の項目は全てSELECT句に記述し、商品マスタの情報は見積品目の「商品」項目からクロスオブジェクト数式を利用して取得しています。

ソースコードをデプロイした実際の画面は下図のようになります。

見積品目の一覧①

画面の動作を確認すると「商品名」「商品コード」「商品ファミリ」の列に値が表示されていません。想定では上記3項目とも値が表示されるので、コーディングをどこか間違えています。まずApexで取得した見積品目のレコードリストをログで確認してみましょう。

見積品目レコードリストのログ

ログを見ると「商品名」「商品コード」「商品ファミリ」項目は取得できています。これらの項目が表示されないのは「lightning-datatable」の列とレコード項目のマッピングができていないことが原因です。

どのようにマッピングされるか下図を確認してください。

項目マッピング①

「lightning-datatable」のdataに設定したレコードリストの各レコードの項目がどの列に表示されるかというのは、「レコードの項目Key(変数名)列情報のfieldName」が成り立つかどうかによって決まります。そしてcolumnsに設定した列情報のfiekdName「Product2.Name」のようにドット演算子を付けてもオブジェクトのプロパティとして認識しません。​

ログを見ると配列構造がよく分かると思いますが、想定通りのマッピングをするためには以下のような構造に変更する必要があります。この構造変換について次のフラット化で詳しく説明します。

レコード構造変換

フラット化

Apexでオブジェクトのレコードを取得し、JavaScript側で受け取った値は多次元配列になっていることが大半です。このような配列の多階層を解除して1次元配列にすることをフラット化といいます。

今回はApexでクロスオブジェクト数式の変数になっている項目を対象にフラット化していきます。
        /**
         * レコードのフラット化
         */
        flatRecord( obj, newObj = {}, aboveKey = "" ) {
                // 連想配列をKeyごとに繰り返し処理
                Object.keys( obj ).forEach( key => {
                        const value = obj[key];
                        const currentKey = aboveKey + key;
                        // 連想配列の場合(ApexのsObject型の場合)
                        if ( typeof value === 'object' && !Array.isArray( value ) ) {
                                // 再帰呼び出し
                                this.flatRecord( value, newObj, currentKey + '.' );
                        } else {
                                // 新しい連想配列にフラット化した項目追加
                                newObj[currentKey] = value;
                        }
                });
                return newObj;
        }
dataTable.js
JavaScriptレコード(sObject型)をフラット化する関数を定義します。引数にレコードを渡すと全ての項目を「Record.Quote.Opportunity.Account.Name」→「Record['Quote.Opportunity.Account.Name']」のようにKeyを置き換えたレコードを返すような処理になっています。階層指定は不要で、再帰呼び出しによって最深部まで読み込みます。

こちらの関数を呼び出す仕様に修正して見積品目の一覧に全項目表示されるか確認します。
        // 見積品目の一覧表示
        @wire ( getQuoteLine, ( { quoteId : '$recordId' } ) )
        setQuoteLineItemList( result ) {
                // Apex正常終了の場合
                if ( result.data ) {
                        console.log( 'result.data:' + JSON.stringify( result.data ));
                        // 以下flatRecord()を呼び出すよう修正
                        // this.dataList = result.data;
                        this.dataList = result.data.map( ( record ) => this.flatRecord( record ) );
                // Apex異常終了の場合
                } else if ( result.error ) {
                        console.log( 'result.error:' + JSON.stringify( result.error ));
                }
        }
dataTable.js
JavaScriptsetQuoteLineItemList関数内で「flatRecord()」を呼び出すように修正しました。
Apexで取得したレコードリストをフラット化したレコードのリストに変換して「lightning-datatable」に設定しています。

見積品目の一覧②

項目マッピング②

画面の動作を確認すると「商品名」「商品コード」「商品ファミリ」の列に値が表示されるようになりました。連想配列になっていたクロスオブジェクト数式項目がJavaScript上でフラット化され、「lightning-datatable」の列情報(columnsfieldName)とマッピングされるようになっています。ソースコード上でも関数を呼び出す処理に1行のみ修正が行われ、複雑化せずスッキリしています。

おわりに

「lightning-datatable​」はレコードのリスト表示が容易にできるため、画面開発を行ううえで利用する機会がよくあります。可読性を意識したコーディングを行うことでメンテナンス性が向上し、後々の作業不可軽減につながるので、この記事を読むことで少しでも皆さんの助けになれば幸いです。

「lightning-datatable」コンポーネントの基本的な使い方は以下の記事を参考にしてください。
32 件
     
  • banner
  • banner

関連する記事