[LWC] 動的インタラクションの例

動的インタラクションはLightningページでのコンポーネント間の連携を、Lightningアプリケーションビルダーから設定できる機能です。
開発者がカスタムコンポーネントを作成し、管理者がコンポーネントを配置してコンポーネント間の連携をカスタマイズするということが可能になります。標準コンポーネントにデータが渡せるのも特徴のひとつです。

## 例
Salesforceのサンプルアプリケーションの[Apex Recipes](https://github.com/trailheadapps/apex-recipes)[^1]を動的インタラクションに変えていきます。

★オリジナル
![dynamic-interactions-01](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125621/73f26852-a4d5-9c4a-12a9-c6109ab91339.png)

[Apex Recipes](https://github.com/trailheadapps/apex-recipes)はApexの作成例を見ることができるアプリケーションです。左のツリーコンポーネントで選択したApexクラスが右のビューアコンポーネントに表示されます。サンプルアプリケーションではツリーコンポーネントとビューアコンポーネントを1つのLWCでラップしています。

このサンプルを動的インタラクションに置き換えていきます。動的インタラクションにすることで、コンポーネントの置き方を変更することができます。
また、標準コンポーネントにもデータを渡すことができます。下記の例では標準の「リッチテキスト」コンポーネントを使用しています。

★動的インタラクション例
![dynamic-interactions-04](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125621/fe0266ca-d399-f633-29b1-0142f5419c6a.png)

### イベントが起こるコンポーネント
変更前のソースコードは[こちら(trailheadapps/apex-recipes)](https://github.com/trailheadapps/apex-recipes/tree/main/force-app/main/default/lwc/recipeTreeView)。
動的インタラクションを使用するためにはイベントを発火する必要があるのですが、**detailをオブジェクトにする必要がある**ので、下記の変更を行います。
カスタムイベントについては→[Lightning Web Component 間の通信の基礎 - Qiita](https://qiita.com/TaaaZyyy/items/ec82c0f048440e904d5e)。


```diff_javascript:recipeTreeView
import { LightningElement, wire } from 'lwc';
import generateTreeData from '@salesforce/apex/RecipeTreeViewController.generateTreeData';

export default class RecipeTreeView extends LightningElement {
    @wire(generateTreeData)
    treeData;

    handleOnSelect(event) {
        event.preventDefault();
+       event.stopPropagation();
        const recipeSelectionEvent = new CustomEvent('select', {
-           detail: event.detail.name
+           detail: { apexName: event.detail.name }
        });
        this.dispatchEvent(recipeSelectionEvent);
    }
}
```

Javascriptで定義したカスタムイベントをxmlに設定します。

- カスタムイベント名（JavascriptのCustomEventの第一引数）を、XMLのevent要素のname属性に設定します。
- カスタムイベントのdetail属性について、XMLのpropertiesで設定します（XMLですが、なぜかjsonで定義する必要があります）。
- typeにはstring、integer、booleanのみ設定できます。
- 今回はapexNameひとつのみですが、複数指定することも可能です。

```diff_xml:recipeTreeView.js-meta.xml
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
+   <masterLabel>Apexレシピセレクタ</masterLabel>
+   <description>Apexの実装サンプルをツリーから選択できるコンポーネントです。</description>
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
    </targets>
+   <targetConfigs>
+       <targetConfig targets="lightning__AppPage">
+           <event name="select" label="Apexクラス選択" description="このイベントはApexクラスを選択した時に発火します。">
+               <schema>
+                   {
+                       "type": "object",
+                       "properties": {
+                           "apexName": {
+                               "type": "string",
+                               "title": "Apex名",
+                               "description": "拡張子を含まないApexクラス名"
+                           }
+                       }
+                   }
+               </schema>
+           </event>
+       </targetConfig>
+   </targetConfigs>
</LightningComponentBundle>
```

ついでにラッパーを使用せずに配置できるようにHTMLも修正します。

```diff_html:recipeTreeView.html
<template>
- <template if:true={treeData}>
+ <article if:true={treeData} class="slds-card">
+   <div class="slds-card__body slds-card__body_inner">
      <template if:true={treeData.data}>
        <div class="slds-p-around_medium lgc-bg">
          <lightning-tree items={treeData.data} header="Groups & Recipes" onselect={handleOnSelect}></lightning-tree>
        </div>
      </template>
      <template if:true={treeData.error}>
        <c-error-panel errors={treeData.error}></c-error-panel>
      </template>
- </template>
+   </div>
+ </article>
</template>
```

### イベントを受け取るコンポーネント
変更前のソースコードは[こちら(trailheadapps/apex-recipes)](https://github.com/trailheadapps/apex-recipes/tree/main/force-app/main/default/lwc/relatedCodeTabs)。
Lightningアプリケーションビルダーで設定値の変更ができるように、xmlファイルにプロパティを定義します。

```diff_xml:relatedCodeTabs.js-meta.xml
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
-   <isExposed>false</isExposed>
+   <masterLabel>Apexレシピビューア</masterLabel>
+   <description>Apexの実装サンプルのビューアです。</description>
+   <isExposed>true</isExposed>
+   <targets>
+       <target>lightning__AppPage</target>
+   </targets>
+   <targetConfigs>
+       <targetConfig targets="lightning__AppPage">
+           <property label="Apex名" name="recipeName" type="String"/>
+       </targetConfig>
+   </targetConfigs>
</LightningComponentBundle>
```

こちらのHTMLもラッパーを使用せずに配置できるようにHTMLも修正します。

```diff_html:relatedCodeTabs.html
<template>
- <template if:true={recipeName}>
+ <article if:true={recipeName} class="slds-card">
+   <div class="slds-card__body slds-card__body_inner">
    <!-- 略 -->
- </template>
+   </div>
+ </article>
</template>
```

### Lightningアプリケーションビルダーでの設定
上記のApexレシピセレクタとApexレシピビューアをLightningページに配置します。Apexレシピセレクタを選択し、インタラクションタブの相互関係を追加から、イベントを受け取るコンポーネントの設定を行います。
![dynamic-interactions-02](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125621/c40264ad-d434-d4d9-1307-04d33a7ffbdd.png)

カスタムしたLWCコンポーネントにイベントを渡す時は下記のように設定します。
![dynamic-interactions-03](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125621/4dc6601b-567d-9831-43c2-4bd70d0bb4a2.png)

標準コンポーネントのリッチテキストにイベントを渡す時は下記のように設定します。
![dynamic-interactions-05](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125621/0db52ee7-0292-ac88-b847-c243bf85ee93.png)

設定後の表示
![dynamic-interactions-04](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125621/fe0266ca-d399-f633-29b1-0142f5419c6a.png)


## 参考
- [Lightning アプリケーションビルダーの動的インタラクション用のコンポーネント設定](https://developer.salesforce.com/docs/component-library/documentation/ja-jp/lwc/lwc.use_config_for_app_builder_dynamic_interactions)
- [Lightning アプリケーションビルダーの動的インタラクション](https://help.salesforce.com/s/articleView?id=sf.dynamic_interactions_overview.htm&type=5)
- [Lightning Web Component 間の通信の基礎 - Qiita](https://qiita.com/TaaaZyyy/items/ec82c0f048440e904d5e)


[^1]:CC0 1.0 Universal