エレメントはイベントを利用することで状態の変化をDOMツリーを介して親エレメントに伝達します。Polymer Elementsは、標準のDOM APIを用いてイベントの生成、ディスパッチ、リッスンを行うことができます。

Polymerにはアノテーション付イベントリスナーも用意されています。このリスナーを使用すれば、エレメントのDOMテンプレートの一部としてイベントリスナーを宣言的に記述できます。

ローカルDOMの子にイベントリスナーを追加するには、テンプレート内でon-event アノテーションを使用します。これにより、イベントリスナーをバインドするためだけにエレメントにidを付与するといった処理が不要になります。

例:

<dom-module id="x-custom">
  <template>
    <button on-click="handleClick">Kick Me</button>
  </template>
  <script>
    class XCustom extends Polymer.Element {

      static get is() {return 'x-custom'}

      handleClick() {
        console.log('Ow!');
      }
    }
    customElements.define(XCustom.is, XCustom);
  </script>
</dom-module>

イベント名はHTML属性を通じて記述されるので、常に小文字に変換されます。これは、HTML属性名が大文字と小文字を区別しないためです。したがって、on-myEventを指定すると、イベントmyEventに対してリスナーが追加されます。イベントハンドラの名前(例えば、handleClick)は大文字と小文字を区別します。混乱を避けるため、常にイベント名には小文字を使用するようにして下さい。

標準のaddEventListener及びremoveEventListenerメソッドを使用して、イベントリスナーを命令的に追加または削除することができます。

Custom Elementにおけるリスナーは、ready()においてthis.addEventListener()を使って設定します。リスナーは、Custom ElementがDOMに初めてアタッチされるときに設定されます。

ready() {
  super.ready();
  this.addEventListener('click', this._onClick);
}

_onClick(event) {
  this._makeCoffee();
}

_makeCoffee () {}

イベントハンドラ内のthisに関して、デフォルトでは、イベントハンドラはthis値を現在のイベントターゲットに設定して呼び出されます。現在のターゲットは、常にイベントリスナーがアタッチされているエレメント(この場合はCustom Element自体)と同一になります。

Custom Elementの子エレメントにリスナーを設定する際は、テンプレート内でアノテーション付きのイベントリスナーを用いる方法が推奨されます。

子エレメントに命令的にリスナーを設定する必要がある場合に重要なことは、 .bind()を使用してthis値をバインドするか、アロー関数を使用することです。

ready() {
  super.ready();
  const childElement = ...
  childElement.addEventListener('click', this._onClick.bind(this));
  childElement.addEventListener('hover', event => this._onHover(event));
}

Custom Elementの外部やその子孫以外(例えば、window)のイベントをリッスンする場合、イベントリスナーを追加したり削除したりするには、connectedCallback()disconnectedCallback()を適切に利用する必要があります。:

constructor() {
  super();
  this._boundListener = this._myLocationListener.bind(this);
}

connectedCallback() {
  super.connectedCallback();
  window.addEventListener('hashchange', this._boundListener);
}

disconnectedCallback() {
  super.disconnectedCallback();
  window.removeEventListener('hashchange', this._boundListener);
}

メモリリークの危険 メモリリークを防止するためdisconnectedCallbackコールバック内でイベントリスナーを削除するようにしてください。自身またはShadow DOMの子のいずれかにイベントリスナーを設定したエレメントは、そのエレメントがガベージコレクトされるのを禁止すべきではありません。しかしながら、ウィンドウまたはドキュメントレベルのような外部のエレメントに設定されたイベントリスナーによって、エレメントがガベージコレクションされないことがあります。

ホストエレメントからカスタムイベントを発火するには、標準のCustomEventコンストラクタとdispatchEventメソッドを使用します。

例:

<dom-module id="x-custom">
  <template>
    <button on-click="handleClick">Kick Me</button>
  </template>

  <script>
    class XCustom extends Polymer.Element {

      static get is() {return 'x-custom'}

      handleClick(e) {
        this.dispatchEvent(new CustomEvent('kick', {detail: {kicked: true}}));
      }
    }
    customElements.define(XCustom.is, XCustom);
  </script>

</dom-module>
<x-custom></x-custom>

<script>
    document.querySelector('x-custom').addEventListener('kick', function (e) {
        console.log(e.detail.kicked); // true
    })
</script>

CustomEventコンストラクタはIEではサポートされていませんが、webcomponents polyfillsには これをサポートするための小さなポリフィルが含まれており、どこでも同じ構文を使って記述することができます。

デフォルトでは、カスタムイベントはShadow DOMの境界で停止します。カスタムイベントがShadow DOMの境界を越えて伝播するようにするには、イベントを作成する際にcomposedフラグをtrueに設定します。:

var event = new CustomEvent('my-event', {bubbles: true, composed: true});

後方互換性 レガシーAPIのインスタンスメソッドfireでは、デフォルトでbubblescomposの両方をtrueが設定されました。最新のAPIで同じように動作させるためには、カスタムイベントを作成する際、上記のように両オプションを指定する必要があります。

Shadow DOMには、イベントがバブルアップする際に、ターゲットを変更する「イベントリターゲッティング(event retargetting)」という機能があり、そのターゲットは常にイベントを受け取るエレメントと同じスコープになります。(例えば、メインドキュメントのリスナーの場合、ターゲットはShadow Tree内ではなくメインドキュメント内のエレメントになります。)

イベントのcomposedPath()メソッドは、イベントが通過するノード群を配列で返します。そのためevent.composedPath()[0]は、イベントの原初のターゲットを表します(ただし、ターゲットが閉じられたShadow Root内に隠れていない場合に限ります)。

例:

<!-- event-retargeting.html -->
 ...
<dom-module id="event-retargeting">
  <template>
    <button id="myButton">Click Me</button>
  </template>

  <script>
    class EventRetargeting extends Polymer.Element {
      static get is() {return 'event-retargeting'}

      ready() {
        super.ready();
        this.$.myButton.addEventListener('click', e => {this._handleClick(e)});
      }

      _handleClick(e) {
        console.info(e.target.id + ' was clicked.');
      }

    }

    customElements.define(EventRetargeting.is, EventRetargeting);
  </script>
</dom-module>


<!-- index.html  -->
  ...
<event-retargeting></event-retargeting>

<script>
  var el = document.querySelector('event-retargeting');
  el.addEventListener('click', function(e){
    // logs the instance of event-targeting that hosts #myButton
    console.info('target is:', e.target);
    // logs [#myButton, ShadowRoot, event-retargeting,
    //       body, html, document, Window]
    console.info('composedPath is:', e.composedPath());
  });
</script>

この例では、原初のイベントが<event-retargeting>エレメントのローカルDOMツリー内の<button>でトリガーされています。リスナーは、メインドキュメント上の<event-retargeting>エレメントに対して設定されています。イベントはリターゲティングされるので、エレメントの実装を隠してしまえばクリックイベントは<button>エレメントからというよりむしろ<event-retargeting>エレメントから生じているようにみえます。

Shadow Rootはdocument-fragmentとしてコンソールに表示されるかもしれません。Shady DOMでは、DocumentFragmentのインスタンスになります。ネイティブのShadow DOMでは、ShadowRoot(DocumentFragmentを拡張するDOMインターフェース)のインスタンスとして表示されます。

詳細は、Shadow DOMのコンセプトのイベントのリターゲティングを参照して下さい.

特定のプロパティ値が変更された際に、ノンバブリングなDOMイベントを発生するエレメントを構築することもできます。詳細については、変更通知イベントを参照してください。