1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Stop Video on Modal Close

Discussion in 'JavaScript' started by 7643sfsag6, May 7, 2020.

  1. #1
    I have several modals, each with a different iframe with a different embedded youtube video.
    When someone closes out of the modal (either by clicking away, hitting ESC or closing it), I would like the youtube video in the modal to stop.

    I am not using bootstrap.

    Below is an example of just one of the modals in action.

    Any suggestions will help!

    Fiddle


    HTML
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <a href="#" class="button" data-modal="#modal2">Modal2</a>
        <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate.</p>
    <div id="modal2" class="modal">
      <div class="modal-content">
        <a class="close">&times;</a>
        <h2>This is an image description 2</h2>
        <div class="video-container"><iframe class="youtube-video" width="560" height="315" src="https://www.youtube.com/embed/3VZFpwlXKpg?enablejsapi=1&mute=0&loop=1&version=3&playerapiid=ytplayer" frameborder="0" allowfullscreen></iframe>
        </div>
        <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate.</p>
      </div>
    </div>
    
    HTML:

    CSS
    
    /* Modal */
    .modal {   position: fixed;   top: 0;   right: 0;   bottom: 0;   left: 0;   z-index: 9999999;   display: none;   background: rgba(255, 255, 255, 0.5); } 
    /* Fullscreen BG */
    .modal-content h2 {font-size: 1.0em; }
    .modal-content {   width: 80%;   height: 80vh;   overflow-x: hidden;   overflow-y: auto;   margin: 10% auto;   font-size: 1.2em; } 
    .close {line-height: 25px;   font-size: 1.0em;   position: absolute;   right: -24px;   text-align: center;   top: -6px width: 24px;   z-index: 9999999;   text-decoration: none;   font-weight: bold;   cursor: pointer; }
    .close:hover { color: grey; }
    /* Youtube */
    .video-container { overflow: hidden; position: relative; width:100%; }
    .video-container::after {padding-top: 56.25%; display: block; content: ''; } 
    .video-container iframe {position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
    
    Code (CSS):

    JS
    //Model
    $(".button").on("click", function() {
      var modal = $(this).data("modal");
      $(modal).fadeIn();
    });
    //click away to close model
    $(".modal").on("click", function(e) {
      var className = e.target.className;
      if (className === "modal" || className === "close") {
        $(this).closest(".modal").fadeOut();
      }
    });
    //ESC close model
    $(document).keydown(function(e) {
      var code = e.keyCode || e.which;
      if (code == 27) $(".modal").fadeOut();
    });
    Code (JavaScript):
     
    Solved! View solution.
    7643sfsag6, May 7, 2020 IP
  2. sarahk

    sarahk iTamer Staff

    Messages:
    28,500
    Likes Received:
    4,460
    Best Answers:
    123
    Trophy Points:
    665
    #2
    Are you able to stop the youtube video if you have a button on the modal?
    If so, then put the code that stops it in the on click function
     
    sarahk, May 7, 2020 IP
  3. 7643sfsag6

    7643sfsag6 Member

    Messages:
    58
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    43
    #3
    ok, but that's the code I'm looking for.

    And it would have to be bound to the three functions above: clicking away, hitting ESC or closing it.
     
    7643sfsag6, May 8, 2020 IP
  4. sarahk

    sarahk iTamer Staff

    Messages:
    28,500
    Likes Received:
    4,460
    Best Answers:
    123
    Trophy Points:
    665
    #4
    The bind is easy.

    So, what you're really looking for is a way to use javascript to pause a youtube video.

    Have you looked at code like https://gist.github.com/cferdinandi/9044694

    What have you tried, what has worked and what hasn't?
     
    sarahk, May 8, 2020 IP
  5. #5
    1) this is 2020, you don't need JavaScript -- much less the incompetent bloated mental-huffing-midgetry of jquery -- to open/close a modal. Either use :target or abuse a hidden checkbox with :checked and a sibling selector. You can ENHANCE it with scripting for something like the escape key, but your primary functionality should NOT be scripting based.

    2) Because the video is in an IFRAME from a different domain, your ability to control it is blocked. On purpose. It's a way browsers try to stop you from making cross domain exploits. As such no, you can't control it so long as it's in that frame. If it were a native VIDEO tag, then you could control it, but YT doesn't give you direct control that way.

    At least for pausing it. If all you want to do is stop it, I'd suggest deleting the iframe or setting its source to empty on close, then recreating it if the user re-opens it.

    Something like:

    
    <div class="modalFix">
    	<h1>Modal Video Demo</h1>
    	<label for="toggle_modal2" class="modalOpen">Modal2</label>
    	<p>
    		Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate.
    	</p>
    <!-- .modalFix --></div>
    <!--
    	.modalFix div lets us overlap scrollbars, that way you don't
    	accidentally end up with two!
    -->
    
    <input type="checkbox" id="toggle_modal2" class="toggleModal" hidden>
    <section class="modal">
    	<div>
    		<label for="toggle_modal2" class="modalClose"></label>
    		<h2>
    			This is an image description 2
    		</h2>
    		<div class="video">
    			<iframe
    				src="https://www.youtube.com/embed/3VZFpwlXKpg?enablejsapi=1&mute=0&loop=1&version=3&playerapiid=ytplayer"
    				frameborder="0"
    				allowfullscreen
    			></iframe>
    		<!-- .video --></div>
    		<p>
    			Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate.
    		</p>
    	</div>
    </section>
    
    Code (markup):
    DIV.modalFix added so that you don't accidentally end up with two scrollbars, using input[checkbox] and labels for our open/close toggles.

    
    /* assuming a reset is in use */
    
    label {
    	cursor:pointer;
    }
    
    .toggleModal {
    	display:block;
    	position:absolute;
    	top:-999em;
    }
    
    .modalFix {
    	padding:1em;
    }
    
    .modalFix,
    .modal,
    .video iframe {
    	overflow:auto;
    	position:absolute;
    	top:0;
    	left:0;
    	width:100%;
    	height:100%;
    }
    
    .modalOpen {
    	text-decoration:underline;
    	color:#00F;
    }
    
    .modal {
    	display:grid;
      justify-items:center;
      align-items:center;
      left:-100%;
      background:rgba(240,240,240,0.8);
      box-shadow:inset 0 0 128px rgba(0,0,0,0.2);
      opacity:0;
      transition:left 0s 0.5s, opacity 0.5s;
    }
    
    .toggleModal:checked + .modal {
    	left:0;
    	opacity:1;
    	transition:left 0s, opacity 0.5s;
    }
    
    .modal > div {
    	position:relative;
    	background:#FFF;
    	padding:1em 1em 0;
    	max-width:48em;
    	box-shadow:
    		0 0 1px rgba(0,0,0,0.5),
    		0 0.25em 0.75em rgba(0,0,0,0.2);
    	border-radius:0.5em;
    }
    
    .modal iframe,
    .modal p {
    	padding-bottom:1em;
    }
    
    .modal h2 {
    	font-size:1.5em;
    	padding:0 2em 0.66em 0; /* right padding makes room for close */
    }
    
    .modalClose:before {
    	content:"\1F5D9";
    	position:absolute;
    	top:0.33em;
    	right:0.33em;
    	font-size:1.5em;
    	line-height:1em;
    	font-weight:bold;
    	color:#F00;
    }
    
    .video {
    	position:relative;
    }
    
    .video:before {
    	content:"";
    	display:block;
    	padding-top:56.25%;
    }
    Code (markup):
    Letting :checked and adjacent sibling selectors do our heavy lifting.

    For the scripting hook:

    
    (function(d, w) {
    
    	var
    		escCloseEvent,
    		toggleModals = d.getElementsByClassName('toggleModal');
    		
    	function modalKey(e) {
    		// use switch for further expansion
    		switch (e.keyCode) {
    			case 27:
    				for (var i = 0, toggle; toggle = toggleModals[i]; i++) toggle.checked = false;
    				break;
    		}
    	} // modalKey
    
    	function toggleModalChange(e) {
    	
    		var
    			videos = e.currentTarget.nextElementSibling.getElementsByClassName('video');
    			
    		if (e.currentTarget.checked) {
    		
    			escCloseEvent = w.addEventListener('keydown', modalKey, false);
    			for (var i = 0, div; div = videos[i]; i++) {
    				if (div['data-modalStoredVideo']) {
    					div.appendChild(div['data-modalStoredVideo']);
    					div['data-modalStoredVideo'] = false;
    				}
    			}
    			
    		} else {
    		
    			if (escCloseEvent) {
    				w.removeEventListener('keydown', modalKey);
    				escCloseEvent = null;
    			}
    			
    			setTimeout(function() {
    				for (var i = 0, div; div = videos[i]; i++) {
    					if (
    						div.firstElementChild &&
    						'IFRAME' === div.firstElementChild.tagName
    					) div['data-modalStoredVideo'] = div.removeChild(div.firstElementChild);
    				}
    			}, 500);
    			
    		}
    		
    	} // toggleModalChange 
    	
    	for (var i = 0, toggle; toggle = toggleModals[i]; i++) {
    		toggle.addEventListener('change', toggleModalChange, false);
    		if (
    			toggle.checked && !escCloseEvent
    		) escCloseEvent = w.addEventListener('keydown', modalKey, false);
    	}
    	
    })(document, window);
    Code (markup):
    Put the whole thing in a IIFE so that the scope is isolated and to pass document and window for faster access and less code.

    First we create a variable to store our event closing hook, so we can add/remove the keyboard intercept since when the modal is closed you might want to intercept the esc key for something else. We then get a nodelist of all modals that we can re-use without doing a (slow) getElementsBy over and over.

    The modal key function I used switch just because you might want to add other functionality in the future, so just add more CASE. This should not trigger often enough for the excess overhead to have any impact.

    toggleModalChange is triggered when the input state's change. First it grabs a list of associated video tags. This allows multiple videos per modal. If the hooked checkbox is checked we add the close event for the ESC key, then loop through all videos.

    I store a hook to the videos in a data- attribute when they are removed, so we can put them back in easily. This is simpler than trying to hook it any other way. Whilst technically data- attribs are supposed to only be strings, if we direct index them ['data-name'] we can use them however the **** we want. Just don't expect them to work with data-list.

    Loop through all the video div, plug in their modalStoredVideo if there is one, then set modalStoredVideo to false so we know it's been done.

    For if it's not checked, we removed the key event listener setting the hook to null (so we don't try to remove an already removed listener!).

    Then we set a timeout so that the video will be removed and stored 500ms after the modal close is triggered. This means that the vidoe won't just "pop" disappearing when you close the modal allowing your CSS animations to fire first.

    We're able to use the videos NodeList inside our event handler because variables in functions declared with var aren't discarded until all references are released. (part of why I think 'let' and 'const' are pointless BS)

    Once we're out of toggleModalChange we just apply all our hooks. First we just add the onchange event, then we see if the toggle is checked and there's no close event. It's possible on a refresh for the input to remain checked but to not have our close handler in place, so we add that.

    End result should be what you're asking for. It removes the video which makes it stop playing and puts it back in if you re-open the modal. By having it there at the start in the markup, the page continues to work for the people who browse with JavaScript or CSS disabled, maximizing accessibility and usability. Remember, good scripting should enhance an already working page, and NOT be your only means of functionality! Do as much as you can without scripting FIRST!

    ... and all without some dipshit framework.

    Live demo here:

    https://cutcodedown.com/for_others/7643sfsag6/modalVideo/

    Hope that helps.
     
    Last edited: May 9, 2020
    deathshadow, May 9, 2020 IP
    malky66 and sarahk like this.
  6. 7643sfsag6

    7643sfsag6 Member

    Messages:
    58
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    43
    #6
    thank you @deathshadow
     
    7643sfsag6, May 9, 2020 IP