What is the best way to add a button click event listener that persists through DOM changes, such as in a single-page application?

I have developed a ViolentMonkey userscript that adds an event listener to a button with the ID #mark-watched. When this button is clicked, it automatically triggers a click on the button with the ID #next-video. This functionality is necessary because the website does not automatically mark videos as watched or move to the next video upon completion.

Below is a simplified representation of the webpage structure where my userscript will be executed:

  <div class="container">
    <button id="next-video" type="button">Next Video</button>
    <button id="mark-watched" type="button">Complete section</button>
  </div>

This is the code snippet for the userscript I created:

  const mark_watched_btn = document.getElementById("mark-watched");
  const next_video_btn = document.getElementById("next-video");

  mark_watched_btn.addEventListener("click", (event) => {
    // wait for 500ms to ensure successful submission of AJAX call marking video as watched
    setTimeout(() => {
      next_video_btn.click();
    }, 500);
  });

The userscript functions correctly when the page initially loads. However, once the page navigates to the next video, the event listener stops working due to the website being built using a JavaScript SAP framework. As a result, when the .container component is reloaded and new buttons are added, the userscript or ViolentMonkey fails to re-execute the script.

Is there a method to dynamically apply my click event listener on #mark-watched to all future buttons that may appear on the page?

Answer №1

One effective technique is to implement event delegation.

document.addEventListener('click', event => {
    if (event.target.matches('#mark-watched')) {
        // process button click
    }
});

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

How can a button be linked directly to a particular list item?

I currently have a HTML tag within my React application that looks something like this: <ul> <li> Item 1 <button> Delete </button> </li> <li> Item 2 <button> ...

Exploring a different method for implementing animations during UI-router state transitions

My product owner presented me with a seemingly impossible challenge to create animations between states. I utilized ngAnimate and thought I had a brilliant solution - only to be told it wasn't what they wanted. "This isn't what I had in mind," h ...

What are the steps to customize the index.html file within the build directory prior to serving it for each request using an Nginx server?

I need to make changes to the React index.html file on the server prior to delivering it to the browser upon request. My goal is to dynamically include open graph meta tags in the head based on the requested URL. Is there a way to accomplish this using N ...

Utilize MySQL/Javascript to determine percentages

I'm facing a challenge with an SQL query in Entrinsik's Informer. I need to calculate a percentage using JavaScript on the result, but unfortunately, Informer cannot access data down columns (such as the total for the percentage). Therefore, I ha ...

Struggling to modify a document in a MongoDB collection with an HTTP Put request?

I've recently started working with AngularJS and I encountered an issue while trying to update my MongoDB Database. I'm facing a problem when attempting to update an object within my collection. The code snippet below showcases my approach: //li ...

I am attempting to change a "+" symbol to a "-" symbol using a Bootstrap toggle feature

Click on the text to reveal more information that drops down below. I am using Bootstrap icons and attempting to show a "+" icon when the toggle is collapsed, and a "-" icon when it's open. I've been trying to use display properties, but haven&ap ...

Is there a way to retrieve the controller instance linked to a directive within the link function?

Is there a way to retrieve the controller instance connected with a directive within the link function? return { template: template, controller: controller, controllerAs: 'myCtrl', // What is the method for ac ...

What is the best way to locate the nearest marker using the Google Maps Direction Service?

Currently, I am engaged in the development of a Google Maps project where I am integrating markers retrieved from a database onto the map using the drawMarkers function. In addition to this, the Google Maps feature tracks your current location and refreshe ...

Tips for verifying conditional input fields in a React component?

As a beginner in React, I attempted to create a SignIn form component that dynamically changes its layout based on a boolean prop toggled between Login and Signup options. In the signup version, there is an additional text field labeled Confirm password, w ...

The jQuery .ajax() function encountered a 405 error stating "Method Not Allowed" when attempting a cross

Despite searching extensively on SO, I am unable to pinpoint the issue in my code. To avoid using JSONP, I am implementing CORS. I understand that this is a preflighted request and believe I have included the correct headers. The problem lies in the web ...

The AJAX call was successful with a return code of 200, however an error

HTML code snippet: <a href="javascript:void(0)" onclick="$.join_group(<?=$USER_ID?>, <?=$groups[$i]["id"]?>)"><?=$language["join"]?></a> JavaScript function: $.join_group = function(user_id, group_id) { var input = "u ...

Using NodeJS, pull JSON data from a JavaScript file and render it in a route file

I am currently utilizing Nodejs Express to work with a script that generates an array of objects from the Google API. My objective is to integrate this JSON data into my templates. How can I invoke the function within my script file from my route file? Be ...

Refresh the jQuery Raty choice when clicked (jQuery)

Currently, I am incorporating the jQuery Raty plugin into a jQuery UI dialog to create a questionnaire-style format. Through custom jQuery scripting, I have devised an interactive interface where users are presented with a new question upon each selection ...

Loading SVGs on the fly with Vue3 and Vite

Currently, I am in the process of transitioning my Vue2/Webpack application to Vue3/Vite. Here's an example of what works in Vue2/Webpack: <div v-html="require('!!html-loader!../../assets/icons/' + this.icon + '.svg')" ...

The data received from the frontend is being replicated in the backend, causing duplication issues in a React

Whenever I click the button labeled onClick, it triggers the transmission of data (both time and ID) to the backend. The issue at hand is that the backend seems to be receiving the data twice instead of just once. On inspecting req.body, it becomes eviden ...

Registering the service worker resulted in an error stating "Undefined is not a function"

When attempting to register a service worker using default React code, I discovered that some users were encountering a `TypeError: undefined is not a function` on the line `.then(registration => {` inside the registerValidSW function. Although it works ...

The functionality of PHP in relation to the jQuery post feature seems to be malfunction

After developing the JavaScript functionality for this contact form, below is the HTML structure without any CSS styling included: <!-- Contact Form --> <div class="cws-widget"> <div class="widget-title" style="color:#fec20b;">S ...

What to do when a JWT token expires and how to generate a fresh token?

I am currently dealing with a problem regarding JWT (JSON Web Token) authentication in my application. At times, when I make API requests, I encounter the following error response: { "success": false, "message": "jwt expired" } I am aware that this er ...

Macy.js, a masonry library, experiences compatibility issues with Internet Explorer 11. However, the problem can be resolved by activating "inspect mode"

Having an issue with macy.js on my website. The masonry element doesn't work on IE11 initially, but when I toggle the "inspect element" feature on and off, it starts working suddenly. Is there a way to trigger it automatically right after the website ...

When using CasperJS to capture multiple screenshots, the most recent screenshot will replace all previous ones

Exploring CasperJS has been a great experience for me. Despite my enjoyment, I've encountered an issue with casper.capture() that has me stumped. I've set it up to capture screenshots whenever a test fails and placed it in a separate setup module ...