JavaScript personalized video controls. Silence the video by manipulating the input range element

As a newcomer to javascript, I am working on creating custom video controls using js. One issue I am facing is with a span element that contains a mute/unmute icon. When I hover over this span element, a child element appears with an input range bar for adjusting the volume level. The problem arises when clicking on the child element (input type range bar), as it causes the icon of the parent element to change and toggles the volume muting and unmuting with each click. How can I resolve this issue?

<html>
    <span id="volbtn" class="fas fa-volume-up">
        <input type="range" value="1" min="0" max="1" volume="1" step="0.1" id="volbar"/>
    </span>
</html>

Event listener:

volCtrl.addEventListener("click", muteVolume);

function muteVolume() {
    if (video.muted) {
        video.muted = false;
        volCtrl.removeAttribute("fa-volume-up");
        volCtrl.setAttribute("class", "fas fa-volume-mute");
    } 
    else {
        video.muted = true;
        volCtrl.removeAttribute("fa-volume-mute");
        volCtrl.setAttribute("class", "fas fa-volume-up");
    }
}

Screenshot

Answer №1

Identifying the primary issue:

The issue lies in your input being wrapped inside a span, causing the event to bubble up to the parent SPAN and triggering mute on input click.


Enhanced handling of custom video events:

While utilizing the older fa icons, you have the freedom to adjust the CSS according to the latest fas specifications.
The JavaScript example provided is quite straightforward, but don't hesitate to seek guidance if needed!

Take note of the newly introduced .is-muted and .is-paused CSS classes!
These classes are essential for the trick, in conjunction with the JS's classList.toggle()

Follow these guidelines:

  • The custom UI elements should purely manipulate the video Element properties.
  • The appearance and styles of custom UI elements should be solely controlled by the events triggered by the video element:

const video   = document.getElementById('video');
const playBtn = document.getElementById('playBtn');
const muteBtn = document.getElementById('muteBtn');
const volBar  = document.getElementById('volBar');

// CUSTOM UI ELEMENTS EVENTS
// They should only change the `video` properties! 
// REMEMBER: we don't handle the UI appearance here
playBtn.addEventListener('click', () => {
  video[video.paused?'play':'pause']();  
});
muteBtn.addEventListener('click', () => {
  if (!video.volume) return;  // Do nothing if there's no volume whatsoever
  video.muted = !video.muted; // Toggle muted state
});
volBar.addEventListener('input', (evt) => {
  video.volume = evt.target.value; 
});

// VIDEO EVENTS - AND UI STYLES
// Triggered on video property value change
// https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
video.addEventListener('play',  handlePlayPauseUI );
video.addEventListener('ended', handlePlayPauseUI );
video.addEventListener('pause', handlePlayPauseUI );
video.addEventListener('volumechange', handleVolumeUI );
// TODO: Handle also 'progress', 'ratechange', etc...

function handlePlayPauseUI () {
  playBtn.classList.toggle('is-playing', !video.paused);
}
function handleVolumeUI() {
  volBar.value = video.muted ? 0 : video.volume;
  muteBtn.classList.toggle('is-muted', video.muted || !video.volume);
}
video {display: block; max-width: 500px;}

.fa {
  user-select: none;
  cursor: pointer;
}

.fa.is-muted:before{           /* I used .fa, you use .fas */
  font-family: "FontAwesome";  /* Fix also the family name if needed */
  content: "\f026";            /* HEX for the "mute" icon (find yours in the cheatsheet CSS docs)*/ 
}

.fa.is-playing:before {
  font-family: "FontAwesome";
  content:"\f04c";             /* set here the HEX for pause icon */
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

<video id="video" autobuffer controls>
  <source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv" type="video/ogg">
  <source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" type="video/mp4">
  <source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm" type="video/webm">
</video>

<span id="playBtn" class="fa fa-fw fa-play"></span>
<span id="muteBtn" class="fa fa-fw fa-volume-up"></span>
<input id="volBar" type="range" value="1" min="0" max="1" volume="1" step="0.1">

By adopting the approach outlined above, it eliminates the distinction whether you interact with the default UI handlers of the video or your custom UI handlers.
With this knowledge in hand, you can proceed to add the missing functions for 'progress', 'ratechange', and other VideoElement Events, and subsequently remove the controls property from the HTML video element.

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

Change the font style of individual characters within a string using CSS or JavaScript, instead of applying it to the entire

Is it feasible to assign a specific font to a particular character? I would like: #test_id{ font-family: "digitalfont"; font-family-of-, : "HelveticaNeue-Light"; } In order to set a font for a comma and a separate font for the rest, do I need to ...

Searching and categorizing information within a table using jQuery

Can someone help me with merging my html and jquery code for type and filter table data, as well as tag data in the same input box? I have the code for both functionalities separately (http://jsfiddle.net/tutorialdrive/YM488/), but I want to combine them. ...

issues with auto-fill functionality in Firefox and Internet Explorer

I am looking to have my username and password automatically filled in when a user is already logged into the website. I have enabled autofill using the code below. Ideally, when a user visits the site again, both the username and password fields should be ...

Utilizing JS Underscore for combining and organizing arrays with common keys

I am facing a scenario where I have two arrays: "array_one": [ { "id": 1, "name": One }, { "id": 2, "name": Two } ] "array_two": [ { "id": 1, "name": Uno }, { "id": 3, "name": Three ...

"Divs are now linked and drag as one cohesive unit instead of

As I was experimenting with making images draggable and resizable, I encountered a small issue. When I attempted to drag two or more images, they would merge into one large draggable object instead of remaining separate. My goal was to make each image drag ...

comparing caching with jquery deferred against promise

Currently, I have implemented code using jQuery Deferred and ajax to fetch data from a remote API, store it in localStorage, and retrieve it from there. However, this code has a bug where it doesn't display the data properly the first time it runs (re ...

Using a batch file to send an email

I have a goal to create an autorun file that can be placed on an external drive, flash disk, or CD. When executed, this file will run a series of commands that eventually send the computer's IP information back to me. Here is what I have so far... Th ...

Passing the v-model property from a child component to a parent in VueJS

Consider a scenario where there is a Vue component structured like the following: Vue.component('child-comp',{ props:['name', 'val'], data: function(){ return { picked: '' } }, ...

Adjust HTML table cell height to dynamically match content and align to top

I am currently working on creating a table layout where the left column adjusts its height based on content, while the right column needs to have a fixed height of 300. <table border="1" cellspacing="0" cellpadding="0"> <tr> <td>&a ...

Looking to have two separate modules on a single page in AngularJS, each with its own unique view

<!DOCTYPE html> <html> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js" ...

Avoid duplicate submissions while still enforcing mandatory fields

Let's start with a basic form that only asks for an email address: <form action="NextPage.php" method="post"> <input type="email" name="contact[email]" required id="frmEmailA" autocomplete="email"> <button type="submit">Subm ...

Executing Statements in a Specific Order with Express and Sqlite3

I am having an issue creating a table and inserting an item into it using the node command. Despite my efforts to reorganize my script, the item is being inserted before the table is created. Interestingly, manually inputting the commands in sqlite3 works ...

Is it possible to pass the index variable of a for loop to a different function?

As a current bootcamp student, I have a question about passing the index of a for loop to another function. Specifically, I am trying to fetch data from an API (which provides me with a random cryptocurrency from an array) 4 times and then pass that data ...

Show a decimal value as an integer in Razor

Looking for assistance with razor code: @Html.DisplayFor(model => item.sepordan_melk_foroshes.ghamat_total) The current output is: 123.00 How can I remove the decimal and display it like this?: 123 Any help with this would be greatly appreciated. ...

Having trouble with my AJAX request and can't figure out why. Anyone available to take a look and help out?

I have successfully implemented this AJAX script on various pages in the past without any issues. <script type="text/javascript" src="jquery-1.4.2.min.js"></script> <script type="text/javascript" src="jquery.validate.min.js"></script& ...

Components will be displayed without any gaps on smaller screens

I attempted to apply styles to two components in order to create space between them, visible on both larger and smaller displays. The code snippet appears as follows: <div> <CustomPageHeader pageTitle={t('offersPage.pageHeader')} ...

I am experiencing difficulty transitioning the view in React Native from a side position to an inward direction

Currently tackling a design project and encountering a roadblock in achieving a specific curved effect. Here are two images for reference: The Desired Design: My Current Progress: The basic structure is in place, but hitting a wall when attempting to cu ...

Using Javascript to validate passwords and Bootstrap for design enhancements

I've been working on learning Javascript and some basic HTML using bootstrap v5 recently. One of the tasks I'm currently tackling is creating a Sign-in form and implementing validation for the required fields. While following the Bootstrap docu ...

Demystifying Iron Ajax: Unraveling the process of parsing an array of JSON objects from a successful

When making an AJAX call to the server, I receive a response in the form of an array of objects as JSON. [{"dms":[{"serialNo":"EG0022","status":"running","firmwareStatus":"ok","latitude":37.8688,"longitude":-144.2093,"toolType":1},{"serialNo":"EG0022","st ...

Can we pause and resume the progress bar using Javascript in conjunction with animationPlayState?

Looking for a way to control a progress bar script that runs for 180 seconds and then redirects the browser? Check out the code snippet below. I've added an onclick event to test pausing the progress bar. My goal is to pause, reset, and adjust the dur ...