Hover video play only plays the last video in the DOM - javascript

I am creating a component where each part has a little video. You hover over the video and it plays is the idea, however only the last video in the HTML actually plays.
Here is the typescript:
document.addEventListener("DOMContentLoaded", videoPlays, false);
function videoPlays() {
var video: HTMLCollectionOf<Element> = document.getElementsByClassName("video");
for(var i = 0; i < video.length ; i++) {
var vid: HTMLVideoElement = video[i] as HTMLVideoElement;
vid.addEventListener("mouseover", (e :MouseEvent) => {
vid.play();
});
vid.addEventListener("mouseout", (e :MouseEvent) => {
vid.pause();
});
}
}
And the html is basically:
<video src="./images/rieky.mp4" class="video" loop></video>
<video src="./images/rieky.mp4" class="video" loop></video>
<video src="./images/rieky.mp4" class="video" loop></video>
<video src="./images/rieky.mp4" class="video" loop></video>
<video src="./images/rieky.mp4" class="video" loop></video>
Strongly assuming its something to do with all the items being the same in terms of their declaration, but I thought the DOM would differentiate by more than just their classname or whatever other properties it has.
Here is a gif of the issue in action. Notice the right hand side flexbox is the only video playing:

This is not a issue but an behavior of variables declared with var statement, i.e. listeners will be attached to each video but they will call play/pause only for last video since the var is function-scoped and it holds only the reference to last item in the loop.
You can fix this by declaring the variables in the loop to be block-scoped with let statement, like so:
function videoPlays() {
var video: HTMLCollectionOf<Element> = document.getElementsByClassName("video");
for(let i = 0; i < video.length ; i++) {
let vid: HTMLVideoElement = video[i] as HTMLVideoElement;
vid.addEventListener("mouseover", (e :MouseEvent) => {
vid.play();
});
vid.addEventListener("mouseout", (e :MouseEvent) => {
vid.pause();
});
}
}

Related

How to let alert happen only once in a for loop using js?

I am trying to use a button to pause the audio element, and the function works fine except the alert() function. The alert just pop up and stays on the top of the website forever.
here is my HTML code
<button id="threeSecTimer">3s</button>
<figcaption>Fire</figcaption>
<audio controls loop>
<source src="xxx" type="audio/mpeg" />
Your Browser doesn't support the audio
</audio>
<figcaption>Forest</figcaption>
<audio controls loop>
<source src="xxx" type="audio/wav" />
Your Browser doesn't support the audio
</audio>
here is js
var threeSecTimer = document.getElementById("threeSecTimer");
var allMusic = document.getElementsByTagName("audio");
function pause3s(e) {
setTimeout(function () {
for (var i = 0; i < allMusic.length; i++) {
if ((allMusic[i] = e.target)) {
allMusic[i].pause();
allMusic[i].currentTime = 0;
alert("time is up!");
}
}
}, 3000);
}
threeSecTimer.addEventListener("click", pause3s);```
You have missed an = in your if condition, change (allMusic[i] = e.target) to (allMusic[i] == e.target)
Your condition, (allMusic[i] == e.target) will never be true since e.target is targeting the 3s button, and allMusic[i] is the audo control. That is assuming you changed the single = to a ==, otherwise the condition will always be true, which is not what you want either, but would lead to the alert button popping up twice, once for each audio control. And when the alert is clicked it should disappear, at least it did for me when I tried out your code.
Perhaps you can check HTML5 check if audio is playing? to target the audio that is playing.

Unable to play an array of videos using javascript

I have an array of video links and i need to play it in a loop back to back.I tried the below link but it did not work for me.
how to display multiple videos one by one dynamically in loop using HTML5 and javascript
My array is
player1=["videoplayback (1).mp4","videoplayback (2).mp4","videoplayback (3).mp4"];
My code is:
function playit()
{
var t=['videoplayback.mp4','videoplayback (1).mp4','videoplayback (3).mp4'];
var myNodelist = document.getElementsByTagName("source");
var i;
for (i = 0; i < myNodelist.length; i++) {
myNodelist[i].src = t[i];
}
}
And this is my html code for video player:
<body onload="playit()">
<video id="video" width="420" autoplay="" loop="" controls="" style="margin-top: 30px;margin-left:40px" >
<source src="" type="video/mp4" id="video1">
<source src="" type="video/mp4" id="video2">
<source src="" type="video/mp4" id="video3">
Your browser does not support HTML5 video.
</video>
</body>
You can do something like include the source files in array and add an event listener, so that each time a video finishes playing it switches to the new source file. The first time you would have to do an onload so that the js function myNewSrc() is called the first time for loading first video. To do that it would look like this:
HTML:
<body onload="myNewSrc()">
<div id="section-title" >
<video preload="auto" onended="myAddListener()" autoplay controls width="480" height="360" title="" poster="https://placehold.it/350x150">
<source src="" type="video/mp4">
</video>
</div>
</body>
JS:
//array of video source files you will be looping through
var videoSources = ["http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4", "http://www.html5videoplayer.net/videos/toystory.mp4", "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4", "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4", "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4"];
var currentIndex = 0;
// listener function changes src
function myNewSrc() {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = videoSources[currentIndex];
myVideo.load();
}
// add a listener function to the ended event
function myAddListener(){
var myVideo = document.getElementsByTagName('video')[0];
currentIndex = (currentIndex+1) % videoSources.length;
myVideo.src = videoSources[currentIndex];
myVideo.addEventListener('ended', myNewSrc, false);
}
You can see a working sample here: https://jsfiddle.net/l33tstealth/pnjchwyf/1/

How do I dynamically change multiple video sources using JavaScript?

I'm trying to dynamically change the video source with the onclick event.
Here's the HTML:
<video autoplay loop poster="1.jpg" id="bg">
<source src="/static/media/1.webm" type="video/webm">
<source src="/static/media/1.mp4" type="video/mp4">
</video>
In onclick I generate a random link, then I change the source of the <video> element:
window.onclick = function() {
var randint = Math.floor(Math.random() * 10) + 1;
var srcmp4 = "http://127.0.0.1:8888/static/media/" + randint.toString() + ".mp4";
document.getElementById('bg').src=srcmp4;
};
If I try to access the source element the same way, by assigning it an id:
<source id="webmid" src="/static/media/1.webm" type="video/webm">
I get null.
I want to dynamically change both .jpg, .webm, .mp4 links. How do I access and assign multiple source elements inside video tag via JS?
The video tag is missing width, height, and controls attributes. Try this:
<video width="320" height="240" id="bg" autoplay loop controls>
<source src="/static/media/1.webm" type="video/webm">
<source src="/static/media/1.mp4" type="video/mp4">
</video>
Additionally here is the new js:
window.onclick = function() {
var randint = Math.floor(Math.random() * 10) + 1;
var srcmp4 = "http://127.0.0.1:8888/static/media/" + randint.toString() + ".mp4";
var video = document.getElementById('bg');
var source = document.getElementByTagName('source');
source = srcmp4;
video.load();
};
After changing that, the source seems to change according to this test.
So i did some reading. First i tried deleting children of video, creating new source elements and appending to video, everything worked in page source, but view didn't render any changes.
So i followed .canPlayType route to determine if client supports .webm, and if not -- assigning mp4 src directly to video element.
Also added small fix so random generated numbers won't repeat. Random video loads when page is loaded and on click events afterwards. Here is the code, it's a mess:
<video autoplay loop poster="" id="bg">
</video>
<script type="text/javascript">
function randlink(a,b){
// generate random int in range of a,b. return str
var c = Math.floor(Math.random()*b)+a;
return "/static/media/"+c.toString();
}
//assign video new random src and poster on page load
window.onload = function(){
var bgvid = document.getElementById('bg');
var randbase = randlink(1,10);
bgvid.poster = randbase + ".jpg";
//check if webm, else mp4 src
if(bgvid.canPlayType('video/webm; codecs="vp8, vorbis"') != ""){
bgvid.src = randbase+".webm";
} else { bgvid.src = randbase+".mp4"}
//change src and poster on click
window.onclick = function() {
var randbase2 = randlink(1,10);
//check if unique
do{
randbase2 = randlink(1,10)
} while (randbase2 == randbase);
randbase = randbase2;
bgvid.poster = randbase2 + ".jpg";
var webmstr = ".webm";
//check if previous was webm, else mp4
if(bgvid.src.indexOf(webmstr) > 0){
bgvid.src = randbase2 +".webm";
}else{
bgvid.src = randbase2 +".mp4";
}}
};
I've already answered this before here: Can I use javascript to dynamically change a video's source?
You have to give the source tags different ids and then add another document.getElementById("source").src = "ANOTHER_SOURCE"; after the first one

HTML5 video custom controls for any number of videos on the page

mates!
I was needed a simple text button – "Play". It should be hidden if video is playing and should be visible when video ends. Everything works fine, but it works only if I have one video on the page with unique ID.
HTML:
<video id="main-video" width="640" height="480">
<source src="media//mp4/video.mp4" type="video/mp4">
</video>
<span id="custom-play-button">Play</span>
And here is the JS:
window.onload = function() {
var video = document.getElementById("main-video");
var playButton = document.getElementById("custom-play-button");
playButton.addEventListener("click", function() {
document.getElementById('main-video').addEventListener('ended',myHandler,false);
video.play();
playButton.style.visibility = "hidden";
function myHandler(e) {
playButton.style.visibility = "visible";
}
});
}
But what should I do if there will be 4,5,6...100 videos on the page (and there will be)? I can't handle with 100 unique ID...
You can put every video and button in a parent div tag as below.
<div class="video-container">
<video id="main-video" width="640" height="480">
<source src="media//mp4/video.mp4" type="video/mp4">
</video>
<span id="custom-play-button">Play</span>
</div>
I'm using jQuery code, you can translate it to plain JS easily.
This should work.
$(".video-container").each(function () {
var video = $(this).find("video");
var plainVideo = video.get(0);/*DOM video object, unwrapped from jQuery*/
var playBtn = $(this).find("span");
playBtn.click(function () {
video.get(0).addEventListener('ended',myHandler,false);
plainVideo.play();
playBtn.css("visibility", "hidden");
function myHandler(e) {
playBtn.css("visibility", "visible");
}
});
});
At least this will give you an idea about the approach to this problem.
With pure Javascript (No jQuery)
You should but depend on the id, use the tag for reference, and get the nearest span. See the below code.
function closest(el, sel) {
if (el != null) return el.matches(sel) ? el : (el.querySelector(sel) || closest(el.parentNode, sel));
}
var videos = document.getElementsByTagName("video");
for (i = 0; i < videos.length; i++) {
var video = videos[i];
var playButton = closest(video, "span");
playButton.addEventListener("click", function () {
document.getElementById('main-video').addEventListener('ended', myHandler, false);
video.play();
playButton.style.visibility = "hidden";
function myHandler(e) {
playButton.style.visibility = "visible";
}
});
}
<video width="640" height="480">
<source src="media//mp4/video1.mp4" type="video/mp4">
</video>
<span class="custom-play-button">Play</span>
<video width="640" height="480">
<source src="media//mp4/video2.mp4" type="video/mp4">
</video>
<span class="custom-play-button">Play</span>
You've got to use CSS classes rather that id's and you have to use JavaScript to listen for video events and have your custom controls such as playpause button toggle. JavaScript's event.target tells you which video is doing what. MDN has a great article Creating a cross-browser video player which includes detailed instructions for custom controls for a single video.
Automated
I spent a few days creating a JavaScript that automates custom controls (Google's Material Design UI) for any number of videos on your HTML page.
The readable source code is on github at rhroyston/material-controls-for-html-video.
Fairly complex to do, but as you can see, it can be done. Live working demo is at https://hightechtele.com/articles/material-controls-for-html-video
Finally, like I said, this took me a few days. It's easy to do by hand for a single video but wanted to automate/script it. ...So view the script (and small accompanied CSS) to see how it can be done.

how to mute Audio/video in website onload for any tag?

i want to mute audio and video sound in my website. the will not be any particular id or class name. it will very that i don't know what the id name can be. so i would like to track via video/object/div/src html tag name and mute the sound.
is this possible by javascript? i have tried the following code; but it does not work. i appreciate your best suggestion.
<!DOCTYPE html>
<html>
<body>
<button onclick="enableMute()" type="button">Mute sound</button>
<video width="320" height="176" controls>
<source src="mov_bbb.mp4" type="video/mp4">
<source src="mov_bbb.ogg" type="video/ogg">
Your browser does not support HTML5 video.
</video>
<script>
var vid = document.getElementsByTagName("video");
function enableMute() {
vid.muted = true;
}
</script>
</body>
</html>
document.getElementsByTagName returns a collection of objects. So if you want to mute them all simply loop through them all and mute them:
document.onload = function() {
var videos = document.getElementsByTagName('video');
for (var i = 0; i < videos.length; i++) {
videos[i].muted = true;
}
var audios = document.getElementsByTagName('audio');
for (var i = 0; i < audios.length; i++) {
audios[i].muted = true;
}
}
Since you tagged the question as jQuery, here is the jQuery variant:
$(document).ready(function() {
$('video, audio').prop('muted', true);
});
Update - How to mute iframes
To mute iframes, it's a bit different. In the same idea, you loop through them but they do not have a mute property.
In JavaScript:
var iframes = document.getElementsByTagName('iframe');
for (var i = 0; i < iframes.length; i++) {
iframes[i].contentWindow.postMessage('{"method":"setVolume", "value":0}', '*');
}
jQuery variant:
$('iFrame').each(function() {
this.contentWindow.postMessage('{"method":"setVolume", "value":0}', '*');
});
JavaScript demo
jQuery demo
It's easy to do using Javascript with jQuery. This method will mute all video elements on the page.
var sound = true;
function muter() {
if (sound === true) {
$("video").prop('muted', true);
sound = false;
$('button').text('Sound');
} else {
$("video").prop('muted', false);
sound = true;
$('button').text('Mute');
}
}
$('button').click(function(){
muter();
});
button{
width:50px;
display:block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Mute</button>
<video width="320" height="240" controls>
<source src="http://www.w3schools.com/tags/movie.mp4" type="video/mp4">
</video>

Categories

Resources