I have several popup modals each with it's own video in autoplay.
Each popups work and close correctly and video autoplays but when I click on the second one, the first one autoplays in the background and the second one doesn't autoplay.
Not sure what I am doing wrong. I have been working on it at:Codepen example
// Get the button that opens the modal
var btn = document.querySelectorAll("a.modal-button");
// All page modals
var modals = document.querySelectorAll(".modal");
// Get the <span> element that closes the modal
var spans = document.querySelectorAll(".close");
// When the user clicks the button, open the modal
let iframe = document.querySelector('iframe');
let player = new Vimeo.Player(iframe);
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function (e) {
e.preventDefault();
modal = document.querySelector(e.target.getAttribute("href"));
modal.style.display = "block";
player.play();
};
}
// When the user clicks on <span> (x), close the modal
for (var i = 0; i < spans.length; i++) {
spans[i].onclick = function () {
for (var index in modals) {
if (typeof modals[index].style !== "undefined")
modals[index].style.display = "none";
player.pause();
}
};
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function (event) {
if (event.target.classList.contains("modal")) {
for (var index in modals) {
if (typeof modals[index].style !== "undefined")
modals[index].style.display = "none";
player.pause();
}
}
};
.modal {
display: none;
padding-top: 100px;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
margin-bottom: auto;
padding: 40px;
border-radius: 8px;
position: fixed;
z-index: 9999999;
}
.modal-content {
background-color: #fff;
padding: 1rem;
border: 1px solid #333;
padding: 40px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
margin: auto;
}
.close {
position: absolute;
right: 0;
top: 0;
transform: rotate(-45deg);
font-size: 28px;
font-weight: bold;
}
iframe {
width: 100%;
height: 100%;
}
<script src="https://player.vimeo.com/api/player.js"></script>
<div class="modal" id="modal1">
<div class="modal-content">
<iframe src="https://player.vimeo.com/video/1053959997?title=0&byline=0&portrait=0&badge=0&autopause=0&player_id=0&app_id=58479" width="1080" height="1620" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media" title="long - dynamic content"></iframe>
</div>
</div>
<div class="modal" id="modal2">
<div class="modal-content">
<iframe src="https://player.vimeo.com/video/1054046699?title=0&byline=0&portrait=0&badge=0&autopause=0&player_id=0&app_id=58479" width="1080" height="1620" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media" title="long - dynamic content"></iframe>
</div>
</div>
<a href="#modal1" class="modal-button">modal 1</a>
<a href="#modal2" class="modal-button">modal 2</a>
SO Snippets block <iframe>
s so of course the example does not function properly. In order to review a functioning example you can copy and paste it into a text file and change the extension from .txt to .html. A copy of the example is also provided at CodePen as well.
A HTMLDialogElement is used instead of a <div>
because the "close" event is used as one of the methods to control the Vimeo player. It's also semantically appropriate and simple to use. The example does a lot more than what is actually needed so I will only address the code that should resolve your problem.
By default the Vimeo player has a autopause
feature enabled. autopause
will allow only one player to play at a time.
When closing a modal the player continues to play. In the example below the player is paused when the "close" event is fired on the <dialog>
. Since your modal has no special events to hook into, try pausing the player when the user clicks outside of the modal or clicks the close button. Do the following:
/**
* First collect all player objects into an array.
* Which you've already done which is great.
*/
let players = iframesArray.map(iframe => new Vimeo.Player(iframe))
/**
* Next, define a function that'll iterate through the
* players array and pause each one.
*/
const pauseAll = () => {
players.forEach((p) => {
p.pause()
.then()
.catch()
});
};
/**
* Finally, add the function to the code block responsible
* for the close button and to the code block that closes
* the modal when the user clicks outside of it.
*/
for (var i = 0; i < spans.length; i++) {
spans[i].onclick = function () {
pauseAll()
....
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Vimeo Playlist Modal</title>
<meta name="description" content="155 chars">
<style>
*,
*::before,
*::after {
box-sizing: border-box;
}
:root {
font: 500 5vmin/1.5 "Segoe UI";
}
body {
overflow: scroll;
}
dialog {
padding: 0;
border: 0;
border-radius: 5px;
background: transparent;
box-shadow: 0 10px 6px -6px #777;
-ms-overflow-style: none;
scrollbar-width: none;
}
dialog::backdrop {
background: rgba(50, 50, 50, 0.3);
}
dialog::-webkit-scrollbar {
display: none;
}
#ui {
padding: 0;
border: 1.5px solid #bbb;
border-radius: 5px;
background: #eee;
}
.btn {
display: inline-flex;
justify-content: center;
align-items: center;
padding: 0;
border: 1px ridge #ddd;
border-radius: 5px;
font: inherit;
font-size: 2rem;
line-height: normal;
background: transparent;
cursor: pointer;
box-shadow: 0 6px 4px -4px #bbb;
}
.btn:hover {
color: #0a87a1;
box-shadow: 0 6px 8px -4px #999;
}
.btn:active {
color: #0a87a1;
transform: scale(0.95);
}
.content {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
width: 100vh;
padding: 0 0.5rem;
border: 0;
background: #eee;
}
.content legend {
width: 100%;
}
.content legend .btn {
float: right;
height: 1.5rem;
margin: 0.25rem -0.25rem 0.25rem 0;
padding-bottom: 0.45rem;
line-height: 0;
color: #888;
}
.control {
display: flex;
justify-content: center;
align-items: center;
margin: 0 0 0.25rem;
padding: 0;
border: 0;
}
#prev,
#next {
width: 2rem;
height: 2rem;
padding: 0;
border: 0;
line-height: 1;
background: #eee;
}
#counter {
padding: 0.75rem 1rem 0;
font-size: 1.25rem;
font-family: Consolas;
color: #0a87a1;
}
#video {
width: 100%;
margin: 0;
padding: 0;
border: 0;
}
.playlist a {
position: relative;
display: list-item;
width: max-content;
color: #18272f;
text-decoration: none;
}
.playlist a+a {
margin-top: 0.5rem;
}
.playlist a::before {
content: "";
position: absolute;
bottom: -0.25rem;
left: 0;
width: 100%;
height: 0.1rem;
border-radius: 4px;
background: #0a87a1;
transform-origin: right;
transform: scaleX(0);
transition: transform 0.3s ease-in-out;
}
.playlist a::marker {
content: "\0000bb\002009";
display: inline-block;
font-size: 1.4rem;
color: #0a87a1;
}
.playlist a:hover::before {
color: #0a87a1;
transform-origin: left;
transform: scaleX(1);
}
.playlist a b {
font-weight: 600;
font-size: 1.1rem;
font-variant: small-caps;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<button id="start">Double Click</button>
<dialog>
<form id="ui" method="dialog">
<fieldset class="content">
<legend>
<input class="btn" type="submit" value="⨯">
</legend>
<fieldset id="video"></fieldset>
<fieldset class="control">
<input id="prev" class="btn" type="button" value="⏮">
<output id="counter"></output>
<input id="next" class="btn" type="button" value="⏭">
</fieldset>
</fieldset>
</form>
</dialog>
<menu class="playlist"></menu>
<script src="https://player.vimeo.com/api/player.js"></script>
<script>
let idx = 0;
let players = [],
links = [],
media,
iframes;
const vIDs = ["148551759", "64142541", "108977978"];
const ui = document.forms.ui;
const io = ui.elements;
const prev = io.prev;
const next = io.next;
const count = io.counter;
const vid = io.video;
const modal = document.querySelector("dialog");
const list = document.querySelector(".playlist");
const setVideos = (vIDs) => {
vIDs.forEach((id) => {
const obj = document.createElement("object");
obj.name = "media";
obj.className = "hidden";
obj.dataset.vimeoId = id;
obj.dataset.vimeoWidth = "720";
vid.append(obj);
players.push(new Vimeo.Player(obj));
});
};
const smallCaps = (str) => {
if (str.includes(" - ")) {
return str.split(/(\s-\s)/)
.map((w, i) => {
return i === 0 ? `<b>${w}</b>` : w;
})
.join("");
} else {
return str.split(" ")
.map((w) => {
return /[A-Z]{2,}/.test(w) ?
`<b>${w[0] + w.slice(1).toLowerCase()}</b>` : w;
})
.join(" ");
}
};
const getTitles = () => {
iframes = [...document.querySelectorAll("iframe")];
media = Array.from(io.media);
return iframes.map((f) => smallCaps(f.title));
};
const setLinks = (titles) => {
titles.forEach((t) => {
const link = document.createElement("a");
link.href = "#";
list.append(link);
link.insertAdjacentHTML("beforeend", t);
links.push(link);
});
};
const pauseAll = () => {
players.forEach((p) => p.pause()
.then()
.catch());
};
const switchMedia = (idx) => {
media.forEach((m) => m.classList.add("hidden"));
pauseAll();
media[idx].classList.remove("hidden");
count.value = idx + 1;
};
const clickList = (e) => {
const clk = e.target;
if (clk.matches("a")) {
idx = links.indexOf(clk);
switchMedia(idx);
modal.showModal();
}
};
list.onclick = clickList;
const reverse = (e) => {
idx--;
idx = idx < 0 ? iframes.length - 1 : idx;
switchMedia(idx);
};
const forward = (e) => {
idx++;
idx = idx > iframes.length - 1 ? 0 : idx;
switchMedia(idx);
};
prev.onclick = reverse;
next.onclick = forward;
modal.onclick = (e) => e.currentTarget.close();
ui.onclick = (e) => e.stopPropagation();
modal.onclose = (e) => pauseAll();
document.getElementById("start").onclick = init;
function init(e) {
setVideos(vIDs);
setLinks(getTitles());
setTimeout(() => this.className = "hidden", 3000);
}
</script>
</body>
</html>