How can I effectively remove event listeners while still preserving the context in a stimulus controller that listens to events multiple times?

My HTML page has the following controller setup:

...
<div data-controller="parent">
    <div data-target="parent.myDiv">
        <div data-controller="child">
            <span data-target="child.mySpan"></span>
        </div>
    </div>
</div>
...

The child controller is linked to the child_controller.js class shown below:

export default class {
    static targets = ["mySpan"];

    connect() {
        document.addEventListener("myEvent", (event) => this.handleMyEvent(event));
    }

    handleMyEvent(event) {
        console.log(event);
        this.mySpanTarget; // Modifying the span works fine.
    }
}

An issue arises when I replace the contents of the target myDiv from my parent_controller.js:

...
let childControllerHTML = "<div data-controller="child">...</div>"

myDivTarget.innerHTML= childControllerHTML;
...

After replacing the child HTML, the event listener triggers twice whenever the myEvent occurs. Subsequent replacements cause the event to be logged multiple times.

I understand that using document.removeEventListener can prevent the old controller from listening to events:

export default class {
    static targets = ["mySpan"];

    connect() {
        this.myEventListener = document.addEventListener("myEvent", (event) => this.handleMyEvent(event));
    }

    disconnect() {
        document.removeEventListener("myEvent", this.myEventListener);
    }

    handleMyEvent(event) {
        console.log(event);
        this.mySpanTarget; // Fails to find span.
    }
}

However, using this approach causes the handleMyEvent method to lose its context as it cannot locate mySpanTarget anymore under this.

Is there a way to remove the listener from the child controller which is no longer in the DOM while maintaining the necessary context?

Answer №1

I came across the solution on a thread in StimulusJS's Discourse forum.

The key is to utilize the bind method during controller initialization:

export default class {
    static targets = ["mySpan"];

    initialize() {
        this.boundHandleMyEvent = this.handleMyEvent.bind(this);
    }

    connect() {
        document.addEventListener("myEvent", this.boundHandleMyEvent);
    }

    disconnect() {
        document.removeEventListener("myEvent", this.boundHandleMyEvent);
    }

    handleMyEvent(event) {
        console.log(event);
        this.mySpanTarget; // Update the span content without any issues.
    }
    ...
}

Thanks to this approach, the event is now only listened to once, ensuring that the context remains intact within the handleMyEvent method.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The 'propTypes' property is not found on the 'typeof TextInput' type declaration

Trying my hand at creating a react-native component using Typescript for the first time, but I ran into an issue on line 51: Property 'propTypes' does not exist on type 'typeof TextInput Couldn't find any helpful information on similar ...

Next.js customization script

How can I efficiently create a class toggle function for a slide-in menu in Next.js? I've developed a menu with a sliding functionality that toggles when a button with the class "toggled" is clicked. However, I'm unsure if this approach aligns w ...

Troubleshooting Angular 2 with TypeScript: Issue with view not refreshing after variable is updated in response handler

I encountered a problem in my Angular 2 project using TypeScript that I could use some help with. I am making a request to an API and receiving a token successfully. In my response handler, I am checking for errors and displaying them to the user. Oddly en ...

Only switch a radio button when the Ajax call results in success

Within an HTML form, I am working with a group of Radio buttons that trigger an Ajax call when the onchange() event is fired. This Ajax call communicates with the server to process the value sent by the call. The response can either be a string of "succes ...

There are a multitude of unfamiliar files within the node_modules directory

I've been following a tutorial by Kent C. Dodds on creating an open source library. In the process, I used npm to install various packages such as chai, commitizen, cz-conventional-changelog, mocha, and unique-random-array. Recently, I noticed that m ...

Is it possible for my code in ReactJS to utilize refs due to the presence of backing instances?

When working with ReactJS components, I often piece together JSX elements to create my code. For example, take a look at the snippet below. I recently came across this page https://facebook.github.io/react/docs/more-about-refs.html which mentions that "Re ...

Perform an HTTP POST request in Angular to retrieve the response data as a JSON object

I am currently in the process of developing a simple user authentication app. After completing the backend setup with Node.js and Passport, I implemented a feature to return JSON responses based on successful or failed authentication attempts. router.pos ...

When formatting amounts, it is important to not allow the thousand separator to come after the decimal separator

I am tasked with ensuring that a thousand separator does not come after a decimal separator every time a key is pressed. Is it feasible to achieve this using regular expressions? If so, can you explain how? ...

Updating serialized $_POST array with new key/value pair using jQuery AJAX

Is there a way to insert additional values into a serialized $_POST array before sending an AJAX request using jQuery? Here's the situation: $('#ajax-preview').on('click', function(e) { e.preventDefault(); var formData = ...

Automatically close the popup each time it is displayed (using jQuery/JavaScript)

I am having issues with auto-closing my popup each time I open it. The current code I have only closes the popup the first time, requiring me to refresh the browser in order to auto-close it again. Can someone please assist me in writing a new code that ...

Achieving proper variable-string equality in Angular.js

In my Angular.js application, I am utilizing data from a GET Request as shown below. var app = angular.module('Saidas',[]); app.controller('Status', function($scope, $http, $interval) { $interval(function(){ ...

Utilizing CSS for styling a class with a dynamic name

On the server side, I am dynamically generating class names like this: <p class="level_1">List item 1</p> <p class="level_2">List item 2</p> <p class="level_3">List item 3</p> <p class="level_1">List item 1</p& ...

What steps should be taken to effectively integrate Amplify Authenticator, Vue2, and Vite?

Embarked on a fresh Vue2 project with Vite as the build tool. My aim is to enforce user login through Cognito using Amplify. However, when I execute npm run dev, I encounter the following issue: VITE v3.1.3 ready in 405 ms ➜ Local: http://127.0.0 ...

The initialization of the Angular service is experiencing issues

I have a service in place that checks user authentication to determine whether to redirect them to the login page or the logged-in area. services.js: var servicesModule = angular.module('servicesModule', []); servicesModule.service('login ...

Adjust the internal state within a Vue3 component using a window function

Creating a "Loader" component that is fully independent and functional just by being included in the layout requires exposing some methods for use. Here is the code I have come up with: <script setup> let active = false; function show() { active ...

Error alert: The function is declared but appears as undefined

Below is the javascript function I created: <script type="text/javascript"> function rate_prof(opcode, prof_id) { $.ajax({ alert('Got an error dude'); type: "POST", url: "/caller/", data: { ...

What is the best way to send an HTML form variable to a Perl script using AJAX?

My goal is to pass the HTML variable from the list menu to the Perl script using POST. However, when I try to do this, the jQuery ajax() function executes the Perl script without including the value obtained from document.getElementById. Below is the sni ...

What could be causing issues with my JavaScript AJAX?

I'm in the process of developing a basic chat system that automatically loads new messages as they come in. Initially, I used to fetch all messages from the database. However, I encountered an issue where the scroll bar would constantly jump to the bo ...

Unable to retrieve hours from MongoDB date array

Whenever I fetch data from my NodeJS+MongoDB webservice, I am able to retrieve the date format successfully. However, I am facing an issue when trying to extract hours from it. Here is how the date looks in MongoDB: https://i.stack.imgur.com/qxWGL.png I ...

The loop is being controlled but the data is not being added and shown in the HTML div

I am struggling to display JSON data in an HTML div using a for loop. While my control is entering the loop, the data is not being appended and displayed in the HTML div. Here is the JSON data: [{"id":"15","FirstName":"ranjan","MiddleName":"","LastName": ...