Handle Events
After you create and dispatch a custom event, you can listen to the event in two ways:
- Attach the event listener declaratively from the component’s HTML template
- Attach the event listener declaratively and dynamically
- Attach the event listener imperatively using JavaScript
It’s better to listen from the HTML template since it reduces the amount of code you have to write. To handle events, define methods in the component’s JavaScript class.
Declare the listener in markup in the template of the owner component, in this example, c-parent.
Define the handler function, in this example handleNotification, in the c-parent JavaScript file.
To declaratively attach multiple event listeners, use the lwc:on directive. Also, use this directive if you want to add event listeners whose event types are computed dynamically, for example, when passed from the owner component via @api.
Pass an object to lwc:on where each property key in the object specifies an event type, and the corresponding property's value is the event handler function. Property keys must be a string, such as click, customEvent, or 'custom-event'.
An event handler that's added using lwc:on is bound to the component instance; this inside the handler refers to the component, allowing access to its properties and methods.
To dynamically add event listeners on a child component, define an object with event types and handlers in the owner component's JavaScript file. Then, use the lwc:on directive in the owner component's template to bind these handlers to the child component.
The eventDynamic component dynamically switches between two event listeners for customEvent and anotherCustomEvent. To toggle the message between the event listeners, click the Switch Event Listener button and then click the Update Message button.
The eventDynamicChild component contains a button that dispatches the custom events.
The eventDynamicChild component dispatches two custom events, customEvent and anotherCustomEvent, when it's connected to the DOM and when the button is clicked. The eventDynamic component attaches the event listeners using lwc:on.
For more information, see Dynamic Event Listeners Considerations.
Define both the listener and the handler function in the c-parent JavaScript.
If the same listener is added to the same element repeatedly, the browser ignores the duplicates.
If the event listener isn’t removed, you can choose to inline the handleNotification code in the addEventListener() call.
Don’t use addEventListener({eventName}, this.handleNotification.bind(this)). It’s an anti-pattern because bind() returns a new function and thus the component can’t call removeEventListener() with the same function instance. Because the component can’t use the same function instance, the listener creates a memory leak.
There are two syntaxes for adding an event listener. One to add an event listener to an element within a component’s shadow boundary, and one to add an event listener to an element that the template doesn’t own, for example, an element passed into a slot.
To add an event listener to an element within the shadow boundary, use template.
To add an event listener to an element that a template doesn’t own, call addEventListener directly.
To get a reference to the object that dispatched the event, use the Event.target property, which is part of the DOM API for events.
Several recipes in the lwc-recipes repo use Event.target. To find examples, search the repo for Event.target.
When an event bubbles up the DOM, if it crosses the shadow boundary, the value of Event.target changes to match the scope of the listener. This change is called “event retargeting.” The event is retargeted so the listener can’t see into the shadow DOM of the component that dispatched the event. Event retargeting preserves shadow DOM encapsulation.
Let’s look at a simple example.
A click listener on <my-button> always receives my-button as the target, even if the click happened on the button element.
Imagine an event is dispatched from a div element in the c-todo-item component. Within the component’s shadow DOM, Event.target is div. But to a listener on the p element in the containing c-todo-app component, the Event.target is c-todo-item, because the p element can’t see into the c-todo-item shadow DOM.
It’s interesting to note that to a listener on c-todo-item, the Event.target is c-todo-item, not div, because c-todo-item is outside the shadow boundary.
To listen for changes from an element in your template that accepts input, such as a text field (<input> or <lightning-input>), use the onchange event.
In this example, the handleChange() method in the JavaScript file is invoked every time the value of the input changes.
The myValue property represents the value for the input element. This property value is not updated automatically on every change.
You might want extra validation of the value the user enters for auto-correction or restriction of some values as they type. To keep myValue synchronized with the current value of the input, update myValue in the handleChange() method. The following auto-corrects the typed value by removing white spaces at the beginning and end of the string. Use evt.target.value to get the current value of the input field.
This example shows how to reset the input value property to the trimmed value in line evt.target.value = trimmedValue. It also shows how to keep myValue property in sync with the normalized value in case the component gets rehydrated (loaded with new values) in the future.
Mutating properties from elements defined through a template could have undesired side effects elsewhere in the component. In our example, the input value property of the element changes from the value defined in the template represented by evt.target. The example changes the value used in the template (myValue) to keep the state of the component elements in sync. Otherwise, template rehydration detects a mismatch of the property value while attempting to reconcile the state of the input element with the state of your component. This mismatch generates a runtime warning, and you need to adapt your component or JavaScript to keep the integrity of the data throughout your template.
The framework takes care of managing and cleaning up listeners for you as part of the component lifecycle. However, if you add a listener to anything else (like the window object, the document object, and so on), you’re responsible for removing the listener yourself.
To remove the event listeners, use the disconnectedCallback lifecycle hook.
If you add an event listener using lwc:on, you could also remove the event listener by omitting that property in the object that's passed to lwc:on.
See Also