Events Firing and Handling

Often child components must notify parent ones that something happened: a button was pushed, a form was confirmed, etc. In Polymer, such notification can be implemented using the standard observer pattern. A child component sends some event and a parent listens to it.

Let’s consider the following example: there is a simple form consisting of an input and a button. Users enter their name and the form notifies the parent component that the form was confirmed and passes the entered name to the parent.

The form

Source code

index.html
<html>
<head>
	<link rel="import" href="src/polymer-basic/events/event-manager.html">
	<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>
</head>
<body>
    <event-manager></event-manager>
</body>
</html>
src/polymer-basic/events/event-manager.html
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="participation-form.html">

<dom-module id="event-manager">
  <template>

    <!-- Here we expect that the component can send an event called 'form-submit'. -->
    <!-- So, the handler attribute is called 'on-form-submit'. -->
    <participation-form on-form-submit="formSubmitted"></participation-form>

  </template>
  <script>
    class EventManager extends Polymer.Element {
      static get is() {
        return 'event-manager';
      }

      formSubmitted(e) {
        // e.detail contains all properties that event sender has provided
        alert(e.detail.name + ', your name has been submitted!');
      }
    }

    customElements.define(EventManager.is, EventManager);
  </script>
</dom-module>
src/polymer-basic/events/participation-form.html
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">

<dom-module id="participation-form">
  <template>

    <iron-input bind-value="{{name}}">
      <input placeholder="Your name" />
    </iron-input>

    <!-- This is another example of how events work in Polymer. -->
    <!-- We just specify a handler in 'on-{event}' attribute. -->
    <button on-click="submitForm">Submit form!</button>

  </template>
  <script>
    class ParticipationForm extends Polymer.Element {
      static get is() {
        return 'participation-form';
      }

      static get properties() {
        return {
          name: String
        }
      }

      submitForm() {
        // Fire a custom event and pass a custom 'name' parameter in it.
        // Our parameter object has to be put inside the 'detail' property of a constructor argument.
        this.dispatchEvent(new CustomEvent('form-submit', { detail: { name: this.name } }));
      }
    }

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

If you have some experience with JavaScript events, you probably noticed that we didn’t put e.stopPropagation() expression into formSubmitted(e) method of the EventManager component. The reason we don’t stop propagation is that there is no propagation since CustomEvents by default do not cross shadow DOM boundaries.

For example, there are Component1, Component2 and Component3. Component1 contains Component2. Component2 contains Component3. Component3 sends some event. In this case Component2 will receive this event and Component1 won’t. This behavior is convenient in most cases but can be changed by using composed property. See more details in the official guide.

What we have learned so far
  • The dispatchEvent(event) method is used to send events. To create an event, we can use CustomEvent constructor which accepts as parameters the event name (mandatory) and a settings object (optional). We can put our custom parameters into the detail property of the settings object.

  • on-{eventName} attributes are used to listen to events.

  • Event parameters can be retrieved using the detail property of an event.