How to stop Vimeo video when Bootstrap modal is dismissed? - javascript

I have a Vimeo modal that works wonderfully and - after some effort - I've gotten the video to stop when the modal is closed via the 'X' button. However, since I put the close function on the 'X' button, if the user clicks away from the video to close the modal rather than using the button, the video keeps playing.
Here is the HTML where I call the stopVideo() function with onclick:
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="stopVideo()">
<span aria-hidden="true">×</span>
</button>
</div>
And here is the Javascript function that stops the video:
<script>
function stopVideo(){
var $frame = $('iframe#nofocusvideo');
// saves the current iframe source
var vidsrc = $frame.attr('src');
// sets the source to nothing, stopping the video
$frame.attr('src','');
// sets it back to the correct link so that it reloads immediately on the next window open
$frame.attr('src', vidsrc);
}
</script>
So, how can I alter the function to apply not to the specific close button, but to any instance where the modal loses focus such as clicking away from the video?
I'm a novice, so go easy on me. Thanks in advance!
EDIT 1:
I've changed the script to the following:
<script>
function stopVideo(){
var $frame = $('iframe#nofocusvideo');
// saves the current iframe source
var vidsrc = $frame.attr('src');
// sets the source to nothing, stopping the video
$frame.attr('src','');
// sets it back to the correct link so that it reloads immediately on the next window open
$frame.attr('src', vidsrc);
}
$('#promo-video').on('hidden.bs.modal', function (e) {
stopVideo();
})
</script>
The stopVideo() function is not being called. Any idea what I'm doing wrong?
EDIT 2:
Here's the code for the modal in question:
<!-- VIDEO MODAL -->
<div class="modal fade" id="promo-video" tabindex="-1" role="dialog" aria-labelledby="modal-video-label">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" onclick="stopVideo()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="modal-video">
<div class="embed-responsive embed-responsive-16by9">
<iframe id="nofocusvideo" src="https://player.vimeo.com/video/180565514?api=1&player_id=vimeoplayer" name="vimeoplayer" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- End Video Modal -->

Here's the working code for it using the default bootstrap id's. Not too sure why yours isn't working.
function stopVideo() {
var $frame = $('iframe#nofocusvideo');
// saves the current iframe source
var vidsrc = $frame.attr('src');
// sets the source to nothing, stopping the video
$frame.attr('src', '');
// sets it back to the correct link so that it reloads immediately on the next window open
$frame.attr('src', vidsrc);
}
$('#myModal').on('hidden.bs.modal', function(e) {
stopVideo();
})
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
<iframe id="nofocusvideo" src="https://player.vimeo.com/video/182738685" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>

A solution that work for me is reload the modal contents:
$("#modal-video").on("hidden.bs.modal", function () {
var url = $('#video-frame').attr('src');
$('#video-frame').attr('src', '');
$('#video-frame').attr('src', url);
});

After a lot of trial and error, changing the javascript to the following solved my problem:
<script>
( function($) {
function iframeModalOpen(){
$('.modalButton').on('click', function(e) {
var src = $(this).attr('data-src');
var width = $(this).attr('data-width') || 640;
var height = $(this).attr('data-height') || 360;
var allowfullscreen = $(this).attr('data-video-fullscreen');
$("#promo-video iframe").attr({
'src': src,
'height': height,
'width': width,
'allowfullscreen':''
});
});
$('#promo-video').on('hidden.bs.modal', function(){
$(this).find('iframe').html("");
$(this).find('iframe').attr("src", "");
});
}
$(document).ready(function(){
iframeModalOpen();
});
} ) ( jQuery );
</script>

I have a series of vimeo player in modal and finally figured out a dynamic way to stop the video after closing the modal. Seriously, bootstrap/vimeo should add this as default!!
$('.modal').on('hidden.bs.modal', function () {
var $this = $(this);
//get iframe on click
var vidsrc_frame = $this.find("iframe");
var vidsrc_src = vidsrc_frame.attr('src');
console.log(`videosrc=` + vidsrc_src);
vidsrc_frame.attr('src', '');
vidsrc_frame.attr('src', vidsrc_src);
});
Have a nice day!

This option is better and dynamic
$(function(){
$('.modal, .close').click(function(){
$("iframe").each(function() {
var src= $(this).attr('src');
$(this).attr('src',src);
});
});
});

Related

How to detect the way Bootstrap modal is closed

I'm attaching handler to the Bootstrap hidden.bs.modal event to detect when the modal is closed, but it can be closed in multiple ways:
Explicitly close it via$('#modal').modal('hide') or $('#modal').modal('toggle');
Clicking on modal's backdrop part (if allowed);
Via data attributes e.g. data-dismiss="modal"
Is there a way to detect which of the options was used? Inside the hidden.bs.modal handler e.target always appears to be div#modal
The thing is that hidden.bs.modal is an event that fires once the modal has been closed. So that is not the click event the user triggered from the close button, the corner X or the overlay...
That said, you can use the click event to store where the user clicked in a variable and milliseconds after, when the hidden.bs.modal fires, use the variable.
Demo:
$(document).ready(function(){
// Variable to be set on click on the modal... Then used when the modal hidden event fires
var modalClosingMethod = "Programmatically";
// On modal click, determine where the click occurs and set the variable accordingly
$('#exampleModal').on('click', function (e) {
if ($(e.target).parent().attr("data-dismiss")){
modalClosingMethod = "by Corner X";
}
else if ($(e.target).hasClass("btn-secondary")){
modalClosingMethod = "by Close Button";
}
else{
modalClosingMethod = "by Background Overlay";
}
// Restore the variable "default" value
setTimeout(function(){
modalClosingMethod = "Programmatically";
},500);
});
// Modal hidden event fired
$('#exampleModal').on('hidden.bs.modal', function () {
console.log("Modal closed "+modalClosingMethod);
});
// Closing programmatically example
$('#exampleModal').modal("show");
setTimeout(function(){
$('#exampleModal').modal("hide");
},1000);
});
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"></script>
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
CodePen
You can use the hide.bs.modal event to capture the document.activeElement. If you have multiple buttons all of which include data-bs-dismiss='modal', this will allow you to determine which of those buttons was pressed. This avoids the need for onclick= approaches or additional event handlers.
It seems it would be more elegant if the Event object for the hide.bs.modal event had a .relatedTarget or similar which contained the triggering element, but alas that's not the case right now.
The example below assumes jQuery with $:
$(() => {
var $dlg = $("#myBootstrapModalDialog");
var $closeElement;
$dlg.on('show.bs.modal', (e) => {
// maybe do something to initialize the modal here...
})
.on('hide.bs.modal', (e) => {
$closeElement = $(document.activeElement);
})
.on('hidden.bs.modal', (e) => {
var id = $closeElement.attr('id');
// do something depending on the id...
if (id === 'btn-save') {
// save something
}
$closeElement = null;
});
});
Sample HTML:
<div class="modal fade"
id="myBootstrapModalDialog"
tabindex="-1"
aria-labelledby="myDialogTitle"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content rounded-0 mx-auto">
<div class="modal-header">
<h3 class="modal-title text-primary" id="myDialogTitle">
Save this stuff?
</h3>
<button id="btn-close" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body px-3">
Are you sure you want to save this stuff?
</div>
<div class="modal-footer">
<button id="btn-cancel" type="button" class="btn btn-link" data-bs-dismiss="modal">
Cancel
</button>
<button id="btn-save" type="button" class="btn btn-secondary" data-bs-dismiss="modal">
Save
</button>
</div>
</div>
</div>
</div>

How to reset position for popup modal with Bootstrap?

I was looking for a solution to my problem and I saw a lot of different ways to do that but none of them worked to me.
I'll paste my code here and see if you can help me somehow.
I have a draggable popup to display a note. There is a list of items on the main screen and everytime the user clicks on the "View" link it opens the popup with the Note for this specific item.
Everything is working properly. The popup opens with the right information and I can move the popup around the screen. Then only problem I have is:
Once I close the popup and open a new one, instead of reseting the popup to the original position it opens exactly where I left the other one. I need to reset the position for the popup when the user closes it.
This is my js:
require(['jquery'
, 'bootstrap'
, 'datepicker'
, 'typeahead'
, 'combobox'
, 'tagsinput'
], function($){
// DOM ready
$(function(){
$('.modal-dialog').draggable();
$('#noteModal').on('show.bs.modal', function(e) {
//get data-id attribute of the clicked element
var note = $(e.relatedTarget).data('note');
//populate the textbox
$(e.currentTarget).find('span[name="note"]').text(note);
});
});
});
This is the modal on my html page:
<!-- Modal to display the Note popup -->
<div class="modal" id="noteModal" tabindex="-1" role="dialog" aria-labelledby="noteModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="noteModalLabel">Note</h4>
</div>
<div class="modal-body">
<span name="note" id="note"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
How can I reset the position for the popup everytime the user closes it?
THank you!
Inside your click handler, you can use JQuery to set the css of the modal like so:
if (!$(".modal.in").length) {
$(".modal-dialog").css({
top: 0,
left: 0
});
}
This will reset the position of your modal. You can use it before you call your modal in your JavaScript, assuming you are using JS to open your modal.
Try running the snippet below or see this CodePen Demo for an example of this using your modal.
// DOM ready
$(function() {
$(".modal-dialog").draggable();
$("#btn1").click(function() {
// reset modal if it isn't visible
if (!$(".modal.in").length) {
$(".modal-dialog").css({
top: 0,
left: 0
});
}
$("#noteModal").modal({
backdrop: false,
show: true
});
});
$("#noteModal").on("show.bs.modal", function(e) {
var note = $('#btn1').data('note');
$(e.currentTarget).find('span[name="note"]').html(note);
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<!-- Modal to display the Note popup -->
<div class="modal" id="noteModal" tabindex="-1" role="dialog" aria-labelledby="noteModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="noteModalLabel">Note</h4>
</div>
<div class="modal-body">
<span name="note" id="note"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<button id="btn1" data-note="I am a note. Hello.">Show Modal</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
If you want to keep the background usable while your modal is open, I posted a solution to this a little while ago here.
I hope this helps!

Detect scroll inside Bootstrap Modal & animate each elements on scroll

I was trying to write a code in which when a bootstrap modal is opened a zoomIn animation is fired on scroll to each element.
jsFiddle Link - https://jsfiddle.net/nwxLq2zg/1/
Here is the sample code -
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
<p>...</p>
<p>...</p>
<p>...</p>
<p>...</p>
...
</div>
</div>
</div>
</div>
jQuery
$('#myModal').on('show.bs.modal', function () {
$(".modal-body").unbind("scroll");
$(".modal-body").scroll(function(){
var mScroll = $(this).scrollTop();
$('.modal-body p').each(function(){
var eTop = $(this).offset().top;
console.log('Modal:'+mScroll+'| Element:'+eTop);
if(eTop > mScroll) {
$(this).addClass('animated zoomIn');
}
});
});
});
Problem is addClass fired to all elements irrespective of scroll value.I doubt this is because my code couldn't identify individual "< p >" tags. If any one can find answer, it would be really helpful.
Actual Code can be found in this jsFiddle - https://jsfiddle.net/nwxLq2zg/1/
I try using <= mScroll and adding -50 on top offset
Check this fiddle.
https://jsfiddle.net/nwxLq2zg/5/
$('#myModal').on('show.bs.modal', function () {
$(".modal-body").unbind("scroll");
$(".modal-body").scroll(function(){
var mScroll = $(this).scrollTop();
$('.modal-body p').each(function(){
var eTop = $(this).offset().top - 50;
if(eTop <= mScroll) {
$(this).addClass('animated zoomIn');
}
});
});
});
You can use Wow.js, it helps revealing information on scroll. All you have to do it download this plugin add the js file in your page and initialize wow on page load.
And in your html you don't need to add classes on run time.
Enjoy :)

Stop YouTube video on modal close - after AJAX load

I have a small script that stops YouTube videos from playing after their modals are closed. The issue is it doesn't work if the HTML has been loaded via AJAX.
Script:
$('#panelModal-1').on('hidden.bs.modal', function () {
callPlayer('yt-player-1', 'stopVideo');
});
$('#panelModal-2').on('hidden.bs.modal', function () {
callPlayer('yt-player-2', 'stopVideo');
});
HTML (curly braces denote data pulled from CMS):
<li>
<a href="#" title="Watch Video" data-toggle="modal" data-target="#panelModal-{count}">
<div class="video-background" style="background-image:url(http://img.youtube.com/vi/{video_youtube_id}/hqdefault.jpg)"></div>
<div class="video-details">
<h4>{title}</h4>
<p>{video_subtitle}</p>
</div>
</a>
<!-- Modal -->
<div class="modal fade" id="panelModal-{count}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel-{count}">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel-{count}">{title}</h4>
</div>
<div class="modal-body">
<div id="yt-player-{count}" class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" src="https://www.youtube.com/embed/{video_youtube_id}?enablejsapi=1"></iframe>
</div>
</div>
</div>
</div>
</div>
</li>
The AJAX part is this:
$(document).ready(function()
{
$('.sub-nav').delegate('.load-case-studies', 'click', function(e)
{
// Don't follow the link
e.preventDefault();
$('.sub-nav a').removeClass('active');
$(this).addClass('active');
// Fetch the next page
$.get($(this).attr('href'), function(data)
{
// Only grab the part of the page we want
content = $(data).find('.ajax-wrapper').hide();
// Add it to the DOM
$(content).replaceAll('#entry-container');
// Fade-in our new content
$(content).fadeIn('fast');
});
});
});
How can I get the videos to stop playing after the modal is closed, if the data has been loaded via AJAX?
you can use following jQuery command.
$('#playerID').get(0).stopVideo();
If your using Player API :
var player = new YT.Player('player');
player.stopVideo();

AngularJS script is running twice

I'm building a script that autoplays a video when a Bootstrap modal opens. I'm using a ng-click on the modal open form, which runs a jquery script withing the angularjs controller.
$scope.startVideo = function (id) {
$(window).on('shown.bs.modal', function() {
console.log('Id nu is: '+id);
var v = document.getElementById("player"+id);
v.play();
console.log('Now playing: player'+id);
});
}
It works fine at first. But when I close the first modal (and stop the video), and fire the script again on another modal, the first video starts, and the second video starts. So now I have 2 video's playing.
The console is giving back: :
Now playing: player1
Now playing: player1
Now playing: player2
The part of the modal which might be interesting:
<div class="modal-body">
{{video.subheader}}<br>
<video id="player{{video.id}}" width="100%" height="100%" controls>
<source src="{{video.videourl+video.ext}}" type="video/mp4></source>
</video>
</div>
<!-- Popup modals below -->
<div id="videomodal{{video.id}}" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">{{video.header}}</h4>
</div>
<div class="modal-body">
{{video.subheader}}<br>
<video id="player{{video.id}}" width="100%" height="100%" controls>
<source src="{{video.videourl+video.ext}}" type="video/mp4"></source>
</video>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Why is the script running twice? I need it to run once when the modal opens. And when I stop the video, close the modal and open another modal, the other modal should start. Not both.
A quick guess would be that your event listeners aren't listening for shown.bs.modal from a specific modal but from any modal on the page. Assuming each modal has its own id (or data attribute or something) based on the id of the video (if they don't have ids you could use the jQuery :has selector - :has('#player'+id) - or something along those lines)
$scope.startVideo = function (id) {
$(window).on('shown.bs.modal', '<modal specific selector>', function() {
console.log('Id nu is: '+id);
var v = document.getElementById("player"+id);
v.play();
console.log('Now playing: player'+id);
});
}

Categories