- JavaScript attaches event listeners to DOM elements and defines the event handlers that specify what should happen when events occur.
- When an event occurs on an element (e.g. a button click), the DOM generates an event object and propagates it through the DOM tree.
# Event propagation
The order in which events are received on the page and propagated through the DOM tree.
There are three event phases:
1. **Event capturing phase**
- Starting from the root of the DOM tree (usually `document`) and travels down the tree.
- Event listeners are only triggered when the third parameter of `addEventListener()`, `useCapture`, is set to true.
2. **Target phase**
- Event listeners are triggered and the target receives the `Event` object.
3. **Event bubbling phase**
- Traveling back up the tree, allowing a final response to the event.
- Event bubbling is more commonly used than event capturing.
- Bubbling allows for **event delegation**, where event listeners are attached to parent elements to handle events triggered by their children. This optimized performance and simplifies code.
![[JavaScript-DOM-Level-2-Event-Steps.png]]
#### Event control and Delegation
- `event.stopPropagation()` is commonly used when you want to prevent an event from bubbling up the DOM tree and being handled by ancestors.
- `event.preventDefault()` prevents the default behavior of an event, such as navigating to a clicked URL.
- Event delegation is a widely used technique where an event is handled by a parent element instead of by individual children. It improves performance and simplifies code.
# Event handling
Event handling refers to the responding to user actions, such as button clicks, submitting a form, or pressing a key, and system events in a web page.
- **Event listeners are the preferred method** to add event handling: `element.addEventListener(event, handler)`
- Event handlers are less flexible and outdated. Handlers are assigned to an element's event property: `element.onclick = ...`
- Only one event handler, per an event type, can be assigned to an element!
- You can also assign event handlers via the HTML event handler attribute but that should be avoided. (Separation of concerns and timing issues.)
```javascript
let btn = document.querySelector('#btn');
// Event listeners are the preferred method of event handling.
function eventListener1(event) {
console.log('First event listener fired');
}
btn.addEventListener('click', eventListener1);
// Multiple listeners can be added to the same element.
// Event listeners / handlers will fire in the order added.
btn.addEventListener('click', function(event) {
console.log('Second event listener fired');
});
// There's also event handlers. Though they're less flexible and outdated.
// Only one event handler, per event type, can be added to an element.
btn.onclick = function() {
console.log('Event handler fired');
};
// Event listeners / handlers fire in the order added.
// If a click event were to occur here. The console would log:
// "First event listener fired"
// "Second event listener fired"
// "Event handler fired"
// You can only remove event listeners with a reference to the specific function.
btn.removeEventListener('click', eventListener1);
// Remove the event handler. (Or replace by assigning another.)
btn.onclick = null;
```
##### Common events
- `click` when an element is clicked.
- `submit` when a form is submitted.
- `load` when a page or an asset (image, script, etc.) has loaded.
- `DOMContentLoaded` when the initial HTML document has been completely loaded and parsed, without waiting for external resources.
- `change` when the value of an input, select, or textarea element has changed.
- And more... `keydown`, `keyup`, `keypress`, `mouseover`, `mouseenter`, `mouseleave`, `scroll` , `resize`, etc...
# Programmatically dispatch events
- Using JavaScript, you can simulate events and trigger the associated event handlers.
- Programmatic dispatch and custom events provide a powerful way to simulate user interactions, trigger actions, and facilitate communication within your application.
- Events dispatched programmatically go through the standard event propagation phases (capturing, target, and bubbling).
To generate an event programmatically:
1. Create a new `Event` using the constructor.
2. Trigger the event using `element.dispatchEvent()`.
```javascript
let btn = document.querySelector('.btn');
// Create an Event. Specify the event type and optional options object.
let event = new Event('click', { bubbles: false, cancelable: false });
// Fire the event on a target element and trigger any event listeners.
btn.dispatchEvent(event);
```
#### Custom events
- Custom events allow you to define your own event types and include additional data with the event.
- Custom events allow you to decouple the code you want to execute after another piece of code completes. For example, you can separate the event listeners in a separate script. Additionally, you can have multiple event listeners to the same custom event.
```javascript
// Create a custom event using the CustomEvent constructor
const customEvent = new CustomEvent('myCustomEvent', {
detail: {
message: 'This is a custom event',
data: { /* Additional data */ }
}
});
// Get the element on which you want to dispatch the custom event
const element = document.getElementById('myElement');
// Dispatch the custom event on the element.
// The event will simulate the full event propagation cycle.
element.dispatchEvent(customEvent);
```