What is the best way to modify a function so that it targets the element that called it?

I utilized the following Bootstrap 4 code to implement a functionality where clicking on a video would play/pause it, and simultaneously toggle a speaker image located below the video.

I am looking for a way to refactor this function so that it only impacts the specific video that was clicked on, and also updates the corresponding image. Is there a method to achieve this using classes?

<div class="col bg-primary p-0" style="width: 100%; max-width: 787px;">
<div class="bg-danger">
<video id="c20-vid" style="width: 100%; max-width: 787px;" preload="metadata" poster="#.png" playsinline loop>
<source src="#.mp4" type="video/mp4">
</video>
</div>
<div class="text-center captions bg-warning">
<img src="img/muted_icon.png" width="15em" id="c20-mute-icon" />
</div>
</div>

Below is the JavaScript used:


function playVideo() {
    // identifies the element that triggered the event
    var video = this;
    var muteIcon = document.getElementById("c20-mute-icon");
    
    if(video.paused) {
        video.play();
        muteIcon.src="img/unmuted_icon.png";
    } 
    else {
        video.pause();
        muteIcon.src="img/muted_icon.png";
    }
}

document.getElementById("c20-vid").addEventListener("click", playVideo);

Answer №1

It appears that you have two objectives:

  1. Create an event handler that understands its calling context without hardcoding it.
  2. Locate an HTML element in relation to another element.

Let's tackle these separately and then demonstrate a combined example.

Developing an event handler with contextual awareness

This is where this comes into play :)

As stated in the MDN article on this:

When a function serves as an event handler, its this is set to the element on which the listener is placed (some browsers may not adhere to this convention for dynamically added listeners using methods other than addEventListener()).

In simple terms, this is a special variable whose value changes based on the function's call location.

This Stack Overflow post delves deeper into scopes and contexts in JavaScript.

Discovering an HTML element relative to another element

A combination of the Element.querySelector function and DOM Node interface's parent/child/sibling properties is typically sufficient for this task.

Merging it all together

Below is a snippet that implements these concepts within your HTML structure (enclosed within an outer div):

// Define event handler
function toggleMute(e) {
    // "this" is derived from the calling context
    // here, it represents the clicked element
    var video = this;
    // obtain the video's parent element and locate the first img element inside it
    var muteicon = video.parentElement.querySelector('img');
    
    // perform actions on these elements
    if(video.muted) {
        video.muted = false;
        video.style.background = "green"
        muteicon.style.background = "yellow";
    } 
    else {
        video.muted = true;
        video.style.background = "orange"
        muteicon.style.background = "teal";
    }
}

// Attach handler to video element, listen for "click" event
document.getElementById('my-vid').addEventListener("click", toggleMute);
video { height: 100px; width: 100px; background: green; }
img { height: 50px; width: 50px; background: yellow; }
<div>
  <video id="my-vid">
      <source src="my.mp4">
  </video>
  <br>
  <img src="img/muted_icon.png" id="speaker-icon" />
</div>

Further options

There are alternative ways to ensure an event handler comprehends its context. You could utilize the event object exposed upon dispatching the event, or explicitly pass this in HTML. Refer to the examples below. Personally, I prefer avoiding inline handlers in HTML, opting for the second or third methods instead.

function ping(target) {
  console.log(target);
  target.classList.toggle('pinged');
  const next = target.nextElementSibling;
  next.classList.toggle('pinged');
  next.nextElementSibling.classList.toggle('pinged');
  
}

function pong() {
  console.log(this);
  this.classList.toggle('ponged');
  this.nextElementSibling.classList.toggle('ponged');
  this.previousElementSibling.classList.toggle('ponged');
}

function pang(e) {
  console.log(e.target);
  e.target.classList.toggle('panged');
  const prev = e.target.previousElementSibling;
  prev.classList.toggle('panged');
  prev.previousElementSibling.classList.toggle('panged');
}

// 'ping' attached to element 'one' inline, in HTML
document.getElementById('two').addEventListener("click", pong);
document.getElementById('three').addEventListener("click", pang);
img {max-height: 200px; max-width: 200px;}
.pinged {filter: sepia(80%)}
.ponged {transform: scale(0.5)}
.panged {opacity: 0.5;}
<img id="one" src="https://www.thewholesomedish.com/wp-content/uploads/2019/06/The-Best-Classic-Tacos-550-500x500.jpg" onclick="ping(this)">

<img id="two" src="https://www.thewholesomedish.com/wp-content/uploads/2019/06/The-Best-Classic-Tacos-550-500x500.jpg">

<img id="three" src="https://www.thewholesomedish.com/wp-content/uploads/2019/06/The-Best-Classic-Tacos-550-500x500.jpg">

Answer №2

In HTML:

<video id=“my-vid" onclick="toggleMute('my-vid', 'my-img');">
    <source src=“my.mp4”>
</video>
<img id="my-img" src="img/muted_icon.png" id=“speaker-icon"  />

In javascipt:

function toggleMute(vid, img) { // argument must be added
  var video = document.getElementById(vid); // utilize the parameter
  var muteicon = document.getElementById(img); // employ the argument
    
  if(video.muted) {
    video.muted = false;
    muteicon.src="img/unmuted_icon.png";
  } 
  else {
    video.muted = true;
    muteicon.src="img/muted_icon.png";
  }
}

I'm uncertain about the correct method to access and mute the video - It's your responsibility to confirm.

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 model's function received the error message "Not a valid function."

My project involves NodeJS, Express, and Sequelize(mysql2)... I am encountering an issue where I keep receiving the error message "is not a function". I have created a model and defined a function in the model as shown below: module.exports = (sequelize, D ...

Automatically update Dropdown options with value and text through an ajax json request

I am working on dynamically populating a dropdown list with text and values fetched using an ajax call to retrieve a JSONObject. While my current code successfully populates the dropdown, I need the value to be different from the text as I intend to store ...

Guide on saving the token in local storage or cookies to grant access to specific web pages for users

Currently, I am in the process of developing an authentication system using Node.js, MySQL, and Express. Initially, I focused on saving and verifying user credentials in the database. Recently, I incorporated JWT (JSON Web Token) into the system. My next s ...

Invoke a specific script snippet by its identifier within a React single-page application, causing the content to appear only upon manual

I am currently working on a React application that utilizes a third-party JS script from OneTrust cookie scripts. Unfortunately, the scripts provided are not optimized for single-page applications (SPAs). At the moment, I am simply referencing the script s ...

Type inference in TypeScript with transitivity

Consider this code snippet for illustration: function foo(t: "number"): number function foo(t: "string"): string function foo(t: "boolean"): boolean function foo(t: "number" | "string ...

Close the Bootstrap burger menu after clicking on a scrollspy link

Is there a way to automatically collapse the Bootstrap burger menu when clicking on a scrollspy link? While browsing my website on a mobile device, the Bootstrap navigation menu switches to a burger icon. However, when you click on an internal link that l ...

Upon the initial data retrieval, everything seems to be working fine. However, when the user transitions to chatting with another user, the state value does not reset and instead shows a combination

Exploring the world of react.js and node.js, I am currently working on developing a chatting application with the integration of socket.io. The issue I'm facing is that when a user clicks on another user to chat, the previous chat messages are display ...

I encountered a permission denied error while attempting to execute the command npm install -g tsc

My main objective is to convert TypeScript code to JavaScript. However, when I attempted to install the TypeScript compiler globally using 'npm install -g tsc', I encountered the following error: npm ERR! Error: EACCES: permission denied, rename ...

What could be causing the ng-submit to fail to trigger the $scope.submit function?

I am currently working on my App.js file which contains the following code snippet: var app = angular.module('githubApp', []); In addition to that, I have a githubAppController with the following code block: app.controller('githubContro ...

What is the most efficient way to clear the input field in Angularjs when the backspace or delete keys are pressed?

Is there a way to reset an input field with AngularJS when the backspace or delete keys are pressed? I've implemented this fantastic directive, and it's been working great, except for when the user uses the backspace or delete key to clear the f ...

What is the most effective way to loop through HTML elements using wildcards in Puppeteer to extract innerText?

Seeking insights for educational purposes, I am in search of the reviews on this specific page . Each page contains 10 reviews, and I have a set of HTML selectors (previously used code) to extract these comments: #review_593124597 > div:nth-child(1) &g ...

The Iframe is preventing the mousemove event from taking place

After attaching an event to the body, a transparent iframe mysteriously appeared in the background of the popup. I am attempting to trigger a mousemove event on the body in order for the popup to disappear immediately when the mouse moves over the iframe ...

Incorporating payment processing into React Native using JavaScript

I am looking to incorporate payment processing into my react native app, but I encountered an issue with using RN's webview as it does not render on the web platform. Additionally, I need to be able to read the response from the server. Can someone re ...

Display the Bootstrap modal only once after a specific portion of the page has been scrolled upon initial

I've almost got this feature working, but I think I'm missing some key logic. My goal is to have a Bootstrap modal appear when a user scrolls to 70% down the page. It's working, but the issue is that when I close the modal, it immediately re ...

Searching for text boxes in Bootstrap dropdown

I've modified a bootstrap template by adding a text box to the navigation bar. My goal is to have this text box display a dropdown list of items automatically as users type, rather than requiring them to manually click search or navigate to another pa ...

Waiting for PHP's return value in JavaScript using AJAX

I am new to AJAX and my objective is to open a PHP file using JavaScript. function verifyInput(user, solution) { return fetch("validateSolution.php", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded; ch ...

Run JavaScript code whenever the table is modified

I have a dynamic table that loads data asynchronously, and I am looking for a way to trigger a function every time the content of the table changes - whether it's new data being added or modifications to existing data. Is there a method to achieve th ...

Substitute a single occurrence of the dollar sign with an HTML tag

I have been attempting to insert an HTML tag into a price on my e-commerce website. Specifically, I am looking to add a tag between the "$" and the numerical value (e.g. $5.00), but I am unable to locate the core file where I can place the code between the ...

I am looking to continuously update a div element on my website with data sourced from another site. My goal is to enable the div element to refresh automatically without

I am looking to continuously update the getPrice($url) function every 1 second without the need for manual page refresh. <?php ini_set('display_errors', '1'); Currently, the getPrice($url) function only refreshes when I manual ...

Utilizing JavaScript to dynamically alter the animation property within CSS

How can I adjust the number of steps in an animation property set within a CSS file? This is the CSS code I am using: #ManSprite{ overflow:hidden; width:200px; height:200px; position:absolute; top:280px; left:140px; background ...