Lightning Component: イベント処理の基本

# はじめに

Lightning Component 開発のキモとなる **イベント（Event）** について、基本的なコードの書き方。

これから Lightning Component 開発を始めてみようと考えている方や、
開発者ガイドを読んだりチュートリアルを試してみたけどいまひとつイベント周りの整理ができていない...という方が対象です。

なお、記事を書いた Spring'15 の時点で Lightning Component はベータ版です。

ref. Lightning Component 開発者ガイド
https://developer.salesforce.com/docs/atlas.ja-jp.lightning.meta/lightning/

# イベントの種類

まず、扱うイベントには 2 つの種類があります。

1. アプリケーションイベント
2. コンポーネントイベント

両者の違いは [Trailhead](https://developer.salesforce.com/trailhead/lightning_components/lightning_components_events_handle) の画像が分かりやすいので、以下でも画像を引用させていただいてます。

### 1. アプリケーションイベント

![ApplicationEvent.png](https://qiita-image-store.s3.amazonaws.com/0/36518/7f5e372f-58c4-56b7-eb52-18285108cbc3.png)

「いわゆる [Publish/Subscribe モデル](http://ja.wikipedia.org/wiki/%E5%87%BA%E7%89%88-%E8%B3%BC%E8%AA%AD%E5%9E%8B%E3%83%A2%E3%83%87%E3%83%AB) に従う」などと Trailhead や開発者ガイドなどでは説明されており、
**異なるコンポーネント間でイベントのやりとりをしたい場合** に使用します。

イベントの送信側は受信側を意識せず、単に自身が定義したイベントを送信するだけ。
そのイベントのハンドラを実装したすべてのコンポーネントがイベントを受信してそれぞれが勝手に処理を行います。

### 2. コンポーネントイベント

![ComponentEvent.png](https://qiita-image-store.s3.amazonaws.com/0/36518/6a9d5a35-2e8f-5896-ccd7-8d53854cf6e7.png)


以下のような場合に使用します。

- コンポーネントが自身の送信したイベントを受信して処理する（図左）
- コンポーネントが別のコンポーネントを含む場合、子のコンポーネントで送信したイベントを親側で受信して処理する（図右）

# イベント処理の流れ

まず、実装までの流れを簡単に書くとこんな感じになります。
（アプリケーションイベント・コンポーネントイベント共通）

1. イベントを作成する（.evt）
2. 送信側：送信するイベントを登録する（.cmp）
3. 送信側：イベントを送信する（.js）
4. 受信側：受信するイベントを登録する（.cmp）
5. 受信側：イベント受信時の処理を記述する（.js）


# イベント実装方法：アプリケーションイベント

**1. イベントを作成する（.evt）**

```xml:appEventMessage.evt
<aura:event type="APPLICATION">
    <aura:attribute name="text" type="String" />
</aura:event>
```

**2.送信側：送信するイベントを登録する (.cmp)**

```xml:appEventSender.evt
<aura:component>
    <aura:registerEvent name="[任意のイベント名]" type="c:[.evtで定義したイベントファイル名]" />
</aura:component>
```

**3. 送信側：イベントを送信（.js）**

アプリケーションイベントは `$A.get()` で取得します。
メソッド名はここでは `send` としてますが任意です。

```js:appEventSenderController.js
({
  send: function(component, event, helper) {
    var appEvent = $A.get('e.c:[.evtで定義したイベントファイル名]');
    appEvent.setParams({
      // key: value
    }).fire();
  }
})
```

**4. 受信側：イベントを登録（.cmp）**

`<aura:handler>` で処理するイベントを登録し、
イベント受信時に実行するコントローラのメソッド名（ここでは `answer`）を `action` で指定します。

```xml:appEventReceiver.cmp
<aura:component>
    <aura:handler event="c:[.evtで定義したファイル名]" action="{!c.answer}" />
</aura:component>
```

**5. 受信側：イベントを受信（.js）**

送信時に `setParams` でセットした値を `getParam(key)` で取得できます。

```js:appEventReceiverController.js
({
  answer: function(component, event, handler) {
    var text = event.getParam(key);
    // 処理
  }
})
```

# イベント実装方法：コンポーネントイベント

**1. イベントの作成（.evt）**

アプリケーションイベントと `type` だけが異なります。

```xml:cmpEventMessage.evt
<aura:event type="COMPONENT">
    <aura:attribute name="text" type="String" />
</aura:event>
```

**2. 送信側：イベントを登録（.cmp）**

```xml:cmpEventSender.cmp
<aura:component>
    <aura:registerEvent name="[任意のイベント名]" type="c:[.evtで定義したイベントファイル名]" />
</aura:component>
```

**3. 送信側：イベントを送信（.js）**

イベントを `component` から取得する点がアプリケーションイベントとは異なります。

```js:cmpEventSenderController.js
({
  send: function(component, event, helper) {
    var messageEvent = component.getEvent('[name=で指定したイベント名]');
    messageEvent.setParams({
      // key: value
    }).fire();
  }
})
```

**4. 受信側：イベントを登録 (.cmp)**

(1) コンポーネントが自身のイベントを処理する場合　と
(2) 子コンポーネントのイベントを処理する場合　とで
記述方法が異なるため、順に説明します。

4.1 コンポーネントが自身のイベントを処理する場合

アプリケーションイベントの時と同じく `<aura:handler>` タグを使いますが、
処理するイベントは `event` ではなく `name` を使い、ファイル名でなくイベント名で指定します。

```xml:cmpEventSender.cmp
<aura:component>
    <aura:registerEvent name="[任意のイベント名]" type="c:[.evtで定義したイベントファイル名]" />
    <!-- 以下を追加 -->
    <aura:handler name="[↑で定義したイベント名]" action="{!c.answer}" />
</aura:component>
```

4.2 子コンポーネントのイベントを処理する場合

親コンポーネント内で子コンポーネントを定義する時に、イベントも定義します。
ここでも、タグ内に記述するのは `.evt` ファイル名ではなく、
送信側の `registerEvent name=` で指定した任意のイベント名です。

```xml:cmpEventReceiver.cmp
<aura:component>
    <c:cmpEventSender イベント名="{!c.answer}" />
</aura:component>
```

**5. 受信側：イベントを受信（.js）**

アプリケーションイベントと同じです。
また、自身のコンポーネントイベントでも子コンポーネントのイベントでも同様です。

```js:appEventReceiverController.js
({
  answer: function(component, event, handler) {
    var text = event.getParam(key);
    // 処理
  }
})
```

# ソースコード

紹介したコードは GitHub で公開しています。

https://github.com/zaki-yama/force-com/tree/master/lightning-event