# Message Channel APIによる連携アプリケーションの開発

Sheetコンポーネントは、SalesforceプラットフォームのLightning Message Serviceの仕組みを通じて、配置されたLightningページ上の他のLightningコンポーネントおよびVisualforceページと相互に連携できます。これにより、Sheetコンポーネント内でのユーザのアクションに連動してページ内の要素を更新したり、逆にページのアクションにしたがってSheetコンポーネントの内容を更新するアプリケーションを作成することが可能です。

{% hint style="info" %}
Sheetコンポーネントと連携するアプリケーションの実現には、Lightningコンポーネントの開発や、Visualforceページの開発などが必要になります。それぞれの開発方法の詳細は、Salesforceの開発ドキュメントを参考にしてください。
{% endhint %}

## イベントの発火とサブスクリプション <a href="#fire-and-subscribe-events" id="fire-and-subscribe-events"></a>

Sheetコンポーネントでのアクションの内容は、外部のプログラムへイベントとして通知することができます。カスタムのプログラムではこのイベントが発行されるMessage Channelをサブスクライブすることにより、Sheetでの動作と連動できます。

Lightning Webコンポーネントの場合、Sheetコンポーネントのイベントをサブスクライブするコードは以下のようになります。

```javascript
import { LightningElement, wire } from "lwc";
import {
  subscribe,
  unsubscribe,
  APPLICATION_SCOPE,
  MessageContext
} from "lightning/messageService";

// シート内のセルにフォーカスした際のイベントを取得するMessage Channel
import MC_FOCUS_CELL from "@salesforce/messageChannel/msmxSheet__focusCell__c";

// イベントをサブスクライブするコンポーネント
export default class MyComponent extends LightningElement {
  @wire(MessageContext)
  messageContext;

  subscr = null;

  connectedCallback() {
    // Message Channelのサブスクライブ
    // 詳細はSalesforceのLightning Webコンポーネント開発のドキュメントを参照
    this.subscr = subscribe(
      this.messageContext,
      MC_FOCUS_CELL,
      (msg) => this.handleFocusCell(msg),
      { scope: APPLICATION_SCOPE }
    );
  }

  disconnectedCallback() {
    // Message Channelのアンサブスクライブ
    if (this.subscr) {
      unsubscribe(this.subscr);
    }
    this.subscr = null;
  }

  handleFocusCell(message) {
    // do something important
    console.log(message.cell.recordId);
  }
}

```

Visualforceページの場合、Sheetコンポーネントのイベントをサブスクライブするコードは以下のようになります。

```html
<apex:page>
  <div>
    <p>Subscribe to SampleMessageChannel </p>
    <button onclick="startSubscription()">Subscribe</button>
    <p>Unsubscribe from subscription</p>
    <button onclick="stopSubscription()">Unsubscribe</button>
    <br/>
    <br/>
    <p>Received message:</p>
    <textarea id="messageReceived" rows="10" />
  </div>
  <script>
    // シート内のセルにフォーカスした際のイベントを取得するMessage Channel
    var MC_FOCUS_CELL = "{!$MessageChannel.msmxSheet__focusCell__c}";
    var subscr = null;

    function handleFocusCell(message) {
      console.log(message.cell.recordId);
      document.querySelector("#messageReceived").value = JSON.stringify(message, null, 2);
    }

    function startSubscription() {
      // Message Channelのサブスクライブ
      // 詳細はSalesforceのVisualforceページ開発のドキュメントを参照
      subscr = sforce.one.subscribe(MC_FOCUS_CELL, handleFocusCell, { scope: "APPLICATION" });
    }

    function stopSubscription() {
      // Message Channelのアンサブスクライブ
      if (subscr) {
        sforce.one.unsubscribe(subscr);
        subscr = null;
      }
    }
  </script>
</apex:page>
```

{% hint style="info" %}
SheetコンポーネントからMessage Channelを通じて外部へイベントを発火するためには、コンポーネントをページ内に配備する際に「Publish Events in Message Channel」プロパティへのチェックが必要になります。
{% endhint %}

## イベントの種別と対応するMessage Channel <a href="#type-of-events" id="type-of-events"></a>

Mashmatrix Sheetでは以下のイベントとそのMessage Channelが現在サポートされています。

### レコード選択 (Select Records) <a href="#event-select-records" id="event-select-records"></a>

シートのレコード選択が変更されたときに通知されるイベント

#### Message Channel名

`msmxSheet__selectRecords__c`

#### イベントメッセージに含まれるデータ

* **componentId** - Sheetコンポーネントを表すページ内で一意のID。Sheetコンポーネントのプロパティ設定の値が設定されます。
* **bookId** - レコード選択イベントが発生したブックのIDを表します
* **sheetId** - レコード選択イベントが発生したシートのIDを表します
* **records** - 選択されたレコードをリスト形式で返します
* **recordIds** - 選択されたレコードのIDをリスト形式で返します

### ロード完了 (Load Complete) <a href="#event-load-complete" id="event-load-complete"></a>

シートのレコードロードが完了したときに通知されるイベント

#### Message Channel名

`msmxSheet__loadComplete__c`

#### イベントメッセージに含まれるデータ

* **componentId** - Sheetコンポーネントを表すページ内で一意のID。Sheetコンポーネントのプロパティ設定の値が設定されます。
* **bookId** - レコードロードが完了したブックのIDを表します
* **sheetId** - レコードロードが完了したシートのIDを表します
* **records** - ロードされたすべてのレコード情報をリスト形式で返します
* **recordIds** - ロードされたすべてのレコードのIDをリスト形式で返します

### セルのフォーカス (Focus Cell) <a href="#event-focus-cell" id="event-focus-cell"></a>

シート内のセルがクリックなどによってフォーカスされたときに通知されるイベント

#### Message Channel名

`msmxSheet__focusCell__c`

#### イベントメッセージに含まれるデータ

* **componentId** - Sheetコンポーネントを表すページ内で一意のID。Sheetコンポーネントのプロパティ設定の値が設定されます。
* **bookId** - フォーカスされたセルが所属するブックのIDを表します
* **sheetId** - フォーカスされたセルが所属するシートのIDを表します
* **cell** - フォーカスされたセルの情報が格納されています
  * **recordId** - セルに表示されているレコードのID
  * **rowIndex** - セルの行インデックス位置（全ページ中）
  * **colIndex** - セルの列インデックス位置
  * **columnName** - セルの列名
  * **value** - セル内に表示されている値
* **record** - フォーカスされたセルがレコード内のセルの場合、そのレコードの情報が格納されます

### カスタムイベントの発行 (Fire Custom Event) <a href="#event-fire-custom-event" id="event-fire-custom-event"></a>

シート内のセルに設定されたカスタムイベントアクションリンクのクリック時、およびカスタムイベントを発行するアクションボタンのクリック時に通知されるイベント

#### Message Channel名

`msmxSheet__fireCustomEvent__c`

#### イベントメッセージに含まれるデータ

* **componentId** - Sheetコンポーネントを表すページ内で一意のID。Sheetコンポーネントのプロパティ設定の値が設定されます。
* **bookId** - カスタムイベントが発行されたブックのIDを表します
* **sheetId** - カスタムイベントが発行されたシートのIDを表します
* **eventName** - アクションボタン/リンクの設定で設定されたイベント名が格納されます
* **records** - （アクションボタンによるカスタムイベントの場合）シート内で選択されているレコードの情報をリスト形式で返します
* **recordIds** - （アクションボタンによるカスタムイベントの場合）シート内で選択されているレコードのIDをリスト形式で返します
* **record** - （アクションリンクによるカスタムイベントの場合）クリックしたリンクを含むレコードの情報が格納されます
* **recordId** - （アクションリンクによるカスタムイベントの場合）クリックしたリンクを含むレコードのIDが格納されます

## パラメーターの設定 <a href="#set-parameters" id="set-parameters"></a>

Lightningページ内に配置されているSheetコンポーネントに対して、外部からパラメータを設定して送信することが可能です。パラメータを利用するには、Sheetコンポーネント内のシートにおいて、フィルタ内の参照値として同名のパラメータ値を参照している必要があります。

イベントのサブスクリプションの場合と同様にMessage Channelを利用しますが、カスタムのプログラムはこのMessage Channelに対してメッセージをパブリッシュすることによってパラメータを設定します。

Lightning Webコンポーネントの場合、Sheetコンポーネントへパラメータを設定するコードは以下のようになります。

```javascript
import { LightningElement, wire } from "lwc";
import { publish, MessageContext } from "lightning/messageService";

import MC_SET_PARAMETERS from "@salesforce/messageChannel/msmxSheet__setParameters__c";

export default class PublishExample extends LightningElement {
  @wire(MessageContext)
  messageContext;

  handleSubmit() {
    publish(this.messageContext, MC_SET_PARAMETERS, {
      parameters: {
        accountName: "Acme"
      }
    });
  }
}
```

Visualforceページの場合、Sheetコンポーネントへパラメータを設定するコードは以下のようになります。

```html
<apex:page>
  <div>
    <input type="text" id="acccountName" value="Acme" />
    <p>Publish to MessageChannel </p>
    <button onclick="publishMessage()">Publish</button>
  </div>
  <script>
    // Sheetに対してパラメータ設定を伝えるMessage Channel
    var MC_SET_PARAMETERS = "{!$MessageChannel.msmxSheet__setParameters__c}";
    function publishMessage(message) {
      sforce.one.publish(MC_SET_PARAMETERS, {
        parameters: {
          accountName: document.querySelector("#acccountName").value,
        }
      });
    }
  </script>
</apex:page>
```

### パラメータ設定用Message Channelの仕様

#### Message Channel名

`msmxSheet__setParameters__c`

#### イベントメッセージに含めるデータ

* **componentId** - パラメータを設定するSheetコンポーネントを表すID。Sheetコンポーネントのプロパティ設定で指定した値を設定します。指定のない場合はページ内のすべてのSheetコンポーネントに対してパラメータを設定します。
* **parameters** - パラメータを指定する任意のJSON形式のオブジェクト。`{ "パラメータ名": "パラメータ値", ... }`の形式となります
* **partial** - パラメータの値をすべて置き換えるのではなく、部分的なアップデートを行う場合に `true` を指定します
* **forceLoad** - アクティブなシートを強制的に再読み込みするように促したいときに `true` を指定します

## コマンドの実行 <a href="#execute-command" id="execute-command"></a>

Lightningページ内に配置されているSheetコンポーネントに対して、外部から操作コマンドを送信することが可能です。

パラメータ設定の場合と同様にMessage Channelに対してメッセージをパブリッシュすることによってコマンドを実行します。

Lightning Webコンポーネントの場合、Sheetコンポーネントへコマンドを送信するコードは以下のようになります。

```javascript
import { LightningElement, wire } from "lwc";
import { publish, MessageContext } from "lightning/messageService";

import MC_EXECUTE_COMMAND from "@salesforce/messageChannel/msmxSheet__executeCommand__c";

export default class CommandExample extends LightningElement {
  @wire(MessageContext)
  messageContext;
  
  @api
  bookId;
  
  sheetId = 's1';

  handleFocusSheet() {
    publish(this.messageContext, MC_EXECUTE_COMMAND, {
      command: "focusSheet",
      arguments: {
        bookId: this.bookId,
        sheetId: this.sheetId
      }
    });
  }
}
```

Visualforceページの場合、Sheetコンポーネントへパラメータを設定するコードは以下のようになります。

```html
<apex:page>
  <div>
    <p>Click to change focus</p>
    <a onclick="focusSheet('s1')">Sheet #1</a>
    <a onclick="focusSheet('s2')">Sheet #2</a>
  </div>
  <script>
    // Sheetに対してパラメータ設定を伝えるMessage Channel
    var bookId = 'your book id is here';
    var MC_EXECUTE_COMMAND = "{!$MessageChannel.msmxSheet__executeCommand__c}";
    function focusSheet(sheetId) {
      sforce.one.publish(MC_EXECUTE_COMMAND, {
        command: "focusSheet",
        arguments: {
          bookId: bookId,
          sheetId: sheetId
        }
      });
    }
  </script>
</apex:page>
```

### コマンド実行用Message Channelの仕様

#### Message Channel名

`msmxSheet__executeCommand__c`

#### イベントメッセージに含めるデータ

* **componentId** - コマンドを実行する対象となるSheetコンポーネントを表すID。Sheetコンポーネントのプロパティ設定で指定した値を設定します。指定のない場合はページ内のすべてのSheetコンポーネントに対してコマンドの実行が要求されます。
* **command** - 実行するコマンド名。
* **arguments** - コマンドに渡す引数。JSON形式のオブジェクトで渡されるが、必要とされる情報は実行するコマンドにより異なる。`{ "引数名": "引数値", ... }`の形式となります。

## 実行可能なコマンドの種別 <a href="#type-of-executable-commands" id="type-of-executable-commands"></a>

Mashmatrix Sheetでは以下のコマンドが現在サポートされています。

### シートのフォーカス <a href="#event-select-records" id="event-select-records"></a>

指定したシートをフォーカスします。対象のシートが非アクティブ（タブの前面にない / 単一表示の対象ではない）である場合、アクティブの状態となり前面に表示されます。指定したシートが非表示状態である場合や存在しない場合には何も実行しません。

#### コマンド名

`focusSheet`

#### コマンド引数

* **bookId** - フォーカスするシートを含むブックのブックID。
* **sheetId** - フォーカスするシートのシートID。

### レコードの保存 <a href="#event-select-records" id="event-select-records"></a>

指定したシートの編集中のレコードデータを保存します。編集中のレコードが存在しない場合には何も実行しません。

#### コマンド名

`saveRecords`

#### コマンド引数

* **bookId** - レコード保存するシートを含むブックのブックID。
* **sheetId** - レコード保存するシートのシートID。

{% hint style="info" %}
アプリケーション読み込み中、ダイアログの表示中など、コマンド実行に支障があるタイミングで送信されたコマンドの実行要求は、要求したプログラム側に通知なく破棄されます。
{% endhint %}
