Skip to content

Custom Events Guide

Steven Steiner edited this page Feb 22, 2021 · 2 revisions

CustomEvent Without Details

This should be used if the component specification has a entry in the 'Events/Outputs' field with nothing in the parentheses.

For example: modalRequest()

Here is an example of a CustomEvent that does not have any data that is passed with the event:

class PomoFinish extends HTMLElement {
    constructor() {
        super();

        // Define the event using 'this.' syntax, so that the event can be referenced outside of the constructor as well.
        this.event = new CustomEvent('modalRequest', {
          bubbles: true, // Required for the event to pass through the Shadow DOM.
          composed: true // Required for the event to pass through the Shadow DOM.
        });

        const shadow = this.attachShadow({mode: 'open'});

        const element = document.createElement('button');

        element.textContent = "Finish";

        element.addEventListener("click", () => {
          shadow.dispatchEvent(this.event); // This is the key line, which causes the event to be dispatched.
        });

        shadow.appendChild(element);
      }
}

customElements.define('pomo-finish', PomoFinish);

To test your event being run successfully, you can add this to control.js:

const finish = document.getElementById('finish'); // Make sure to reference the component by its id

finish.addEventListener('modalRequest', () => {
    console.log('modalRequest');
})

CustomEvent With Details

This should be used if the component specification has a entry in the 'Events/Outputs' field with something in the parentheses.

For example: modalRequest(count: number) (this doesn't actually exist in our timer)

Here is an example of a CustomEvent that does have any data that is passed with the event:

class PomoFinish extends HTMLElement {
  constructor() {
      super();

      this.testVariable = 1;

      // Define the event using 'this.' syntax, so that the event can be referenced outside of the constructor as well.
      this.event = new CustomEvent('modalRequest', {
        bubbles: true,
        composed: true,
        detail: {count: () => this.testVariable} // Data needs to be stored as a function, so it refreshes each time the event runs
      });

      const shadow = this.attachShadow({mode: 'open'});

      const element = document.createElement('button');

      element.textContent = "Finish";

      element.addEventListener("click", () => {
        this.testVariable++; // This is just used so that the number changes when testing the example.
        shadow.dispatchEvent(this.event);
      });

      shadow.appendChild(element);
    }
}

customElements.define('pomo-finish', PomoFinish);

To test your event being run successfully, you can add this to control.js:

const finish = document.getElementById('finish'); // Make sure to reference the component by its id

finish.addEventListener('modalRequest', (event) => {
    console.log('modalRequest', event.detail.count()); // The data is accessible at 
})

Quick Note on Functions

JS has two ways of declaring functions:

function test() {

}

and

test = () => {

}

The second method, commonly referred to as an "arrow function", is able to access this this variable of surrounding code. It's needed for these examples so that the event and other variables can be access correctly. This doesn't match the function style we have set for our overall codebase, so only use the arrow functions if you also need to access the this variable.

Clone this wiki locally