背景
LMS (Lightning Message Service)を利用してみたいという気持ちはずっとありましたが、Parent-Child間でほぼ済んでいたので、無関係なコンポーネント間のデータのやり取りニーズは正直ありませんでした。
今回その必要性が出てきたのですが、その前に、標準の関連リストが簡単でお気に入りである一方、どうしても一括編集などができないのでlightning-datatableのonrowactionやdraft-valuesを利用した一括編集のできる関連リスト(LWC)をカスタムで作成していました。
そこで、さらにQuickActionからFlowを起動して複数の関連レコードを作成する機会があり、QuickActionからフローを起動してレコードを作成したのですがここで問題が発生です。
標準リストでは新規に作成したレコードも含めてリストを自動で更新しますが、カスタム関連リストでは更新しません。これは、なにかしらLWCヘ新規レコードが作成されたということを通知する必要があり、LMSで解決できそうではないかと思ったわけです。
結果
結果は、LMSでFlowのステータスが「FINISHED」が帰ってきた時にpublishし、カスタム関連リストのLWCにその旨を通知して、subscribe側のLWCで再度情報を取得するメソッドを走らせることで、リストが無事更新されることになりました。標準関連リストに寄せてカスタムを作成すると大変だなぁという感想です。
ただこのLMSは取得したデータをどんな型でも送れるので、あるコンポーネントのデータ群を親子関係でない別のコンポーネントへ送って描画する場合にも利用できるのではないかと考えています。
デモ
- LWCを起動する
Quick Contact
のQuick Actionボタンを押すと、LWCのModalが出現して、データをInputします。(Screen Flow) - Flowを完了するとlightning-flowのonstatuschangeで、
FINISHED
のステータスがLWCに戻ってきて、MessageChannelでpublishします。 - MessageChannelを通じて別のLWCが通知をsubscribeして、
データ更新
のメソッドを走らせます。今回はshowToastでSubscribedした旨も通知です。
構成
Screen Flow * 1
Quick Action * 1
Class * 1
LWC * 2
Message Channel * 1
以上です。
手順
1. Flowを内包したLWCを作成
<template>
<lightning-card title={title} icon-name={iconName}>
<div class="slds-m-top_small">
<lightning-flow lwc:if={recordId} flow-api-name={flowName} flow-input-variables={inputVariables}
onstatuschange={handleFlowFinish}></lightning-flow>
</div>
</lightning-card>
</template>
2. QuickActionからはLWC経由でフローを起動
Flow API Name はこちらを参照
Screen Flowで入力画面から値を代入
3. Flowが終わったらフローのステータスを取得
handleFlowFinish(event) {
if (event.detail.status === "FINISHED") {
const message = {
recordId: this.recordId,
status: event.detail.status,
};
this.dispatchEvent(new CloseActionScreenEvent());
// Publish the message
publish(this.messageContext, FINISH_FLOW_CHANNEL, message);
}
}
recordIdですが、通常は@api recordId
で取得できますが、今回はScreen Action (Ui action)なので、renderedされて初めて取得されます。よってgetter, setterで設定します。と同時にinputVariablesにそのrecordIdを取得後挿入して、lightning-flowを起動します。
inputVariables = [];
_recordId;
@api
get recordId() {
return this._recordId;
}
set recordId(value) {
if (value !== this._recordId) {
this._recordId = value;
this.inputVariables = [
{
name: "recordId",
type: "String",
value: value,
},
];
}
}
4. LMSにmessageを送信
上記と合わせてpublishするためにjsにimportしておきます。
Publish側 (createContactQuickAction)
import { publish, MessageContext } from "lightning/messageService";
import FINISH_FLOW_CHANNEL from "@salesforce/messageChannel/finishFlow__c";
5. カスタム関連リストがLMS経由でpublisherのmessageを受け取る
Subscribe側 (getContactList)
import { subscribe, MessageContext } from "lightning/messageService";
import FINISH_FLOW_CHANNEL from "@salesforce/messageChannel/finishFlow__c";
6. 情報取得methodを動かして更新
messageが来るのを@wire
で監視します。
@wire(MessageContext)
messageContext;
subscription = null;
subscribeToChannel() {
// Subscribe to the message channel
if (this.subscription) {
return;
}
this.subscription = subscribe(
this.messageContext,
FINISH_FLOW_CHANNEL,
(message) => this.handleMessage()
);
}
// Subscribing to the message channel debug
handleMessage() {
this.handleGetContacts(); // to refresh the datatable
const params = {
message: "Subscribed Successfully",
mode: "dismissable",
variant: "success",
};
this.handleShowToast(params);
}
参照
Use Quick Actions - Screen Flow (Salesforce)
Lightning Flow (Salesforce)
Lightning Datatable (Salesforce)
LMS Component Library (Salesforce)
Lightning Message Service(LMS)を触ってみました (TerraSky)
まとめ
これは以前の投稿した商品の値段や個数を自由に変更できる「商品追加ボタン」を作ってみた (lwc)での商談商品の再取得にも利用できそうです。
標準ではFlowで作成した新規はすぐに関連リストに表示されます。Inline Editをさせてくれれば最高なんですが、それゆえにListEditorとかの利用需要があるものわかります。
自動更新は、Master-detailの集計項目があればそれを@wire
で絡めて、新規データが追加されるごとのデータ取得を走らせることもできます。今回は単にLookup関係でもできるようにしました。
難易度的には簡単な方から:
related list
mater-detail relationship with @wire
-
Lightning Message Service
でした。
Lightning Message Serviceを学べてとても楽しかったです。
githubにコードを公開しておきますので、もしアイディアのある方がいたらぜひ。
https://github.com/liuxiachanghong/lightning-message-service