I have some divs that I use jQuery's fade in/out to bring onto the page when a link is clicked. Each page has an associated html5 audio element that also fades in/out accordingly.
$('.link').on('click', function(e){
var targetpage = $($(this).attr("href"));
$('.pagecontainer>div').fadeOut(0); //fade out currently displayed page
targetpage.fadeIn(); //fade in page associated with link
if (targetpage.children().hasClass('backgroundmusic')) {
$('audio').animate({volume: 0}, 1000); //fade out currently playing audio
alert('audio faded out');
$.each($('audio'), function () { //stop all audio
this.currentTime=0;
this.pause();
alert('audio stopped');
});
alert('stop function executed');
}
});
$('.sound').on('play', function () { //since volume was faded out, reset volume when click play button
$('audio').animate({volume: 1}, 100);
});
HTML:
Audio 1
Audio 2
Audio 3
<div class="pagecontainer">
<div id="page1"> //all three audio elements are in exact same spot
//clicking page link fades in current audio and fades in new one
<div class="backgroundmusic">
<audio controls loop class="sound" preload="none">
<source src="../../site/music/music1.mp3"/>
<source src="../../site/music/music1.ogg"/>
</audio>
</div>
</div>
<div id="page2">
<div class="backgroundmusic">
<audio controls loop class="sound" preload="none">
<source src="../../site/music/music2.mp3"/>
<source src="../../site/music/music2.ogg"/>
</audio>
</div>
</div>
<div id="page3">
<div class="backgroundmusic">
<audio controls loop class="sound" preload="none">
<source src="../../site/music/music3.mp3"/>
<source src="../../site/music/music3.ogg"/>
</audio>
</div>
</div>
</div>
The "alert('audio faded out')" will execute, but the "alert('audio stopped')" does not execute as it's not running the "$.each($('audio'), function" script at all, neither does "alert('stop function executed')". I have to use this "each" script as $('audio').currentTime=0 does not work, neither does $('audio').pause(), as I have multiple audio instances on my page.
Does anyone know why this is not working?
Thanks.
You pass in e to your function but don't use it. Probably want to prevent default action from that click event.
e.preventDefault(); //Put this at the top of the callback
This should fix your .each() problems. Also you should be using the console instead of alerts as to not freeze your page.
console.log('audio faded out'); //Use console instead of alerts
$('audio').each(function () { //Do it this way.
this.currentTime=0;
this.pause();
console.log('audio stopped');
});
console.log('stop function executed');
Related
JS newbie here. I'm in a situation where I need each video in a set to play on mouseover and pause on mouseout. I use a forEach loop to give this functionality to all of them, but now I need to "move" this functionality to div containers for each video, not the videos themselves.
Here's what I'm starting with:
HTML
<video src="/path-to-video" loop></video>
<video src="/path-to-video" loop></video>
<video src="/path-to-video" loop></video>
<video src="/path-to-video" loop></video>
JS
const videos = document.querySelectorAll('video');
videos.forEach(video => {
video.addEventListener('mouseover', function () {
this.play();
});
video.addEventListener('mouseout', function () {
this.pause();
});
});
I need to "transfer" the functionality of the above to a div container for each video. So, when I hover over the video, it is the div container that is actually playing the video, and when I hover away, it is the div container that is pausing the video. So NOT the video itself like it is above.
The HTML would now look like this (essentially):
<div class="item">
<video src="/path-to-video" loop></video>
</div>
<div class="item">
<video src="/path-to-video" loop></video>
</div>
<div class="item">
<video src="/path-to-video" loop></video>
</div>
<div class="item">
<video src="/path-to-video" loop></video>
</div>
I tried this JS:
const items = document.querySelectorAll('.item');
items.forEach(item => {
const video = document.querySelectorAll('video');
item.addEventListener('mouseover', function () {
video.play();
});
item.addEventListener('mouseout', function () {
video.pause();
});
});
This did nothing; none of the videos played on hover.
I also tried:
document.querySelector('.item').addEventListener('mouseover', function () {
const video = document.querySelector('video');
video.play();
});
document.querySelector('.item').addEventListener('mouseout', function () {
const video = document.querySelector('video');
video.pause();
});
This worked as intended on the first video, but not any of the others, and using querySelectorAll made none of them work. Using getElementsByClassName makes none of them work.
I'd prefer to keep the forEach approach but just have each div play and pause its video child using mouseover and mouseout. How could this be achieved? I'm probably not doing something obvious.
items is a NodeList, so you are looping over all of the elements with the "item" class. You can use the querySelector method on the elements you're iterating over to get that element's child video element. Then, you can call play() on that video element.
Basically, you had the right idea, you just need to use querySelector on the item instead of document.
Example:
const items = document.querySelectorAll('.item');
items.forEach(item => {
// see change below
const video = item.querySelector('video');
item.addEventListener('mouseover', function() {
video.play();
});
item.addEventListener('mouseout', function() {
video.pause();
});
});
.item {
width: 300px;
}
video {
width: 300px;
}
<div class="item">
<video src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4" loop></video>
</div>
<div class="item">
<video src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4" loop></video>
</div>
<div class="item">
<video src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4" loop></video>
</div>
<div class="item">
<video src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4" loop></video>
</div>
I'm trying to make it so that when you click on a separate element it pauses the current song playing from a different element. In addition I had previously made it so when you click on the same element after it started playing audio it would pause that audio, but when you click on a different element with the same function it breaks.
var paused = true;
var song;
var songPlaying;
function playSong(x) {
song = x;
if(songPlaying != song){
document.getElementById(songPlaying).pause();
}
if(paused == true){
document.getElementById(song).play();
paused = false;
songPlaying = song;
} else {
document.getElementById(song).pause();
paused = true;
}
}
Is there anyway I can fix this? Will I have to make a different function for every song?
EDIT 1: Here the HTML my for the sections I'm using as well, each audio file has an ID that is called as a parameter in the function inside onclick
<div class="album">
<img src="assets/BattalionsOfFear.png" onclick="playSong('bofSong')">
<h1>Battalions of Fear</h1>
<p>Released in 1988</p>
</div>
<div class="album">
<img src="assets/FollowTheBlind.png" onclick="playSong('bfsSong')">
<h1>Follow the Blind</h1>
<p>Released in 1989</p>
</div>
<!--- Audio -->
<audio id="bofSong">
<source src="assets/BattalionsOfFear.mp3">
</audio>
<audio id="bfsSong">
<source src="assets/BanishFromSanctuary.mp3">
</audio>
EDIT 2:
In attempting Laif's solution
I have tried adding the 'song' class to my HTML img elements and linked it to my audio element with the 'song1' class yet it still is not working. Am I doing the classes wrong or is it something with the way I have put them down?
<div class="album">
<img src="assets/BattalionsOfFear.png" class="song song1">
<h1>Battalions of Fear</h1>
<p>Released in 1988</p>
</div>
<audio id="bofSong" class="song1">
<source src="assets/BattalionsOfFear.mp3">
</audio>
Each song should share the same class so that you can do something like this:
<html>
<div class="song"></div>
<div class="song"></div>
</html>
var songs = document.querySelectorAll(".song");
function playSong(e) {
songs.forEach(el => {
el.style.play();
});
e.currentTarget.pause();
};
songs.forEach(el => {
el.addEventListener("click", playSong);
});
I'm struggling trying to set a mouseenter and mouseleave event in several videos. Everything seems that work perfectly, the video plays when I mouseenter and stop when mouseleave.
However, when I add more than one video, just play the first video. I am trying to figure out what it's missing what I don't find the way to do it.
Here is the link to codepen: https://codepen.io/felixgonzalo/pen/poJoXRW
My code is:
<div class="main-wrapper">
<div class="video-container">
<video id="video" class="video" controls class="border" controls="false" muted loop>
<source src="https://www.errorerror.studio/wp-content/uploads/2020/01/ee.st-honesty-clip-00.mp4" preload="auto" type="video/mp4" autoplay />
</video>
<div class="overlay"></div>
</div>
<div class="video-container">
<video id="video-2" class="video" controls class="border" controls="false" muted loop>
<source src="https://www.errorerror.studio/wp-content/uploads/2020/01/ee.st-honesty-clip-00.mp4" preload="auto" type="video/mp4" autoplay />
</video>
<div class="overlay"></div>
</div>
</div>
jQuery
$('.video').prop('currentTime', 0)
function Play() {
$('.video').get(0).play();
}
function Stop() {
$('.video').prop('currentTime', 0).get(0).pause();
}
$(document).ready(function(){
$('.video-container').mouseenter(function(){
$('.overlay', this).addClass("hide")
Play();
}).mouseleave(function(){
$('.overlay', this).removeClass("hide")
Stop();
});
});
I also tried to make it in JS but didn't work out:
var container = document.querySelector('.video-container');
container.addEventListener('mouseleave', function() {
this.querySelector('.overlay').classList.remove('hide');
Stop();
});
container.addEventListener('mouseenter', function() {
this.querySelector('.overlay').classList.add('hide');
Play()
});
Really appreciate any help
Your function play gets only the first video because you specified the 0 index. You need to pass the current video index you're hovering to trigger the playback.
EDIT: Working code.
I made your functions taking an argument, which I'm setting to the first video element children of the element triggering the mouse events.
$('.video').prop('currentTime', 0)
$(document).ready(function() {
$('.video-container').mouseenter(function() {
$('.overlay', this).addClass("hide")
$(this).children('.video')[0].play();
}).mouseleave(function() {
$('.overlay', this).removeClass("hide")
$($(this).children('.video')[0]).prop('currentTime', 0)
$(this).children('.video')[0].pause();
});
});
I am trying to fade in an icon when video finish, but nothing.
Html
<video>
<source src="">
</video>
<div class="icon"></div>
First Try
$("video").on("ended", function() {
$(".icon").fadeIn;
});
Second try
$('video').parent().on("ended", function() {
if($(this).children("video").get(0).paused) {
$(this).children(".icon").fadeIn();
}
});
Actually has onclick event working fine
$("video").parent().on("click", function() {
$(this).children(".icon").fadeToggle();
});
You can try this way:
<video id="myVideo">
<source src="">
</video>
<div class="icon"></div>
var vid = document.getElementById("myVideo");
vid.onended = function() {
alert("The video has ended"); //Just to verify if the event is trapped
$(".icon").fadeIn();
};
You can achieve it in this way
document.getElementById('video').addEventListener('ended',function() {
$(".icon").fadeIn();
},false);
You've all been so great in helping me in the past and I'm hoping we can solve this next problem as well.
I am building a slideshow of sorts using videos as backgrounds instead of images. Everything is working perfectly except that the timing of the videos is off because even though my divs are hidden the videos are all playing at the same time.
So, what I need is a JS/jQuery solution to stop (not pause) and play the videos as the divs are hidden/shown. Here's my code so far:
jsfiddle: http://jsfiddle.net/Z2Nq8/1/
JS:
$(function () {
var counter = 0,
divs = $('#video1, #video2, #video3');
function showDiv () {
divs.hide()
.filter(function (index) { return index == counter % 3; }) // figure out correct div to show
.show();
counter++;
};
showDiv();
setInterval(function () {
showDiv();
}, 7 * 1000);
});
HTML:
`<div id="videocont">
<div id="video1" class="display">
<video autoplay loop poster="PHI.png" id="bgvid">
<source src="URL/video.mp4" type="video/mp4">
</video>
<div id="title">Headline text.
</div>
</div>
<div id="video2" class="display">
<video autoplay loop poster="PHI.png" id="bgvid">
<source src="URL/video.mp4" type="video/mp4">
</video>
<div id="title">Headline text.
</div>
</div>
<div id="video3" class="display">
<video autoplay loop poster="PHI.png" id="bgvid">
<source src="URL/video.mp4" type="video/mp4">
</video>
<div id="title">Headline text.
</div>
</div>
</div>`
Thanks!
You have auto play on all of the videos.
Set auto play on the first element, then when you're going through the videos use:
VideoElement.play()
And
VideoElement.pause()
If you want to then reset the video you can do:
VideoElement.currentTime = 0;
To manage the videos playing.
Working Fiddle