89

I have a hidden div containing a YouTube video in an <iframe>. When the user clicks on a link, this div becomes visible, the user should then be able to play the video.

When the user closes the panel, the video should stop playback. How can I achieve this?

Code:

<!-- link to open popupVid -->
<p><a href="javascript:;" onClick="document.getElementById('popupVid').style.display='';">Click here</a> to see my presenting showreel, to give you an idea of my style - usually described as authoritative, affable and and engaging.</p>

<!-- popup and contents -->
<div id="popupVid" style="position:absolute;left:0px;top:87px;width:500px;background-color:#D05F27;height:auto;display:none;z-index:200;">

  <iframe width="500" height="315" src="http://www.youtube.com/embed/T39hYJAwR40" frameborder="0" allowfullscreen></iframe>

  <br /><br /> 
  <a href="javascript:;" onClick="document.getElementById('popupVid').style.display='none';">
  close
  </a>
</div><!--end of popupVid -->
Rob W
  • 341,306
  • 83
  • 791
  • 678
0161-Jon
  • 1,001
  • 1
  • 8
  • 3

14 Answers14

194

The easiest way to implement this behaviour is by calling the pauseVideo and playVideo methods, when necessary. Inspired by the result of my previous answer, I have written a pluginless function to achieve the desired behaviour.

The only adjustments:

  • I have added a function, toggleVideo
  • I have added ?enablejsapi=1 to YouTube's URL, to enable the feature

Demo: http://jsfiddle.net/ZcMkt/
Code:

<script>
function toggleVideo(state) {
    // if state == 'hide', hide. Else: show video
    var div = document.getElementById("popupVid");
    var iframe = div.getElementsByTagName("iframe")[0].contentWindow;
    div.style.display = state == 'hide' ? 'none' : '';
    func = state == 'hide' ? 'pauseVideo' : 'playVideo';
    iframe.postMessage('{"event":"command","func":"' + func + '","args":""}', '*');
}
</script>

<p><a href="javascript:;" onClick="toggleVideo();">Click here</a> to see my presenting showreel, to give you an idea of my style - usually described as authoritative, affable and and engaging.</p>

<!-- popup and contents -->
<div id="popupVid" style="position:absolute;left:0px;top:87px;width:500px;background-color:#D05F27;height:auto;display:none;z-index:200;">
   <iframe width="500" height="315" src="http://www.youtube.com/embed/T39hYJAwR40?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
   <br /><br />
   <a href="javascript:;" onClick="toggleVideo('hide');">close</a>
Community
  • 1
  • 1
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • 1
    Yup definitely need the green checkbox if this worked. I'm taking this solution too - great stuff, I have these video frames in an jQueryUI Accordion so I need to attach it to each trigger event. – jeffkee Jul 20 '12 at 03:09
  • Just wanted to point out that, sadly, YouTube's API does make you use double quotes for the message sent through postMessage. You can't switch to have outer double quotes and inner single quotes, for example. – Jordan Dec 14 '12 at 21:45
  • 1
    @Jordan That perfectly makes sense because the message is expected to be JSON. JSON, by definition, uses double quotes to quote keys and values. – Rob W Dec 14 '12 at 21:49
  • Yup, I understand the format. I just wish it wasn't that way still :) – Jordan Dec 15 '12 at 04:37
  • I just tried this one and it works well in chrome but fails in firefox. Show video restarts the video from the beginning instead of starting from the paused position. Any suggestions. Thanks – Ramesh Oct 18 '13 at 01:36
  • @Ramesh Instead of hiding the container, move it off screen. E.g. using http://jsfiddle.net/ZcMkt/350/ – Rob W Oct 18 '13 at 09:24
  • it's somehow wont working on FF 26.0 any idea on the workaround? – bondythegreat Jan 30 '14 at 01:19
  • FF workaround that works on me: setTimeout(); it needs time in document.ready i believe. http://jsfiddle.net/bondythegreat/4VLBS/2/ – bondythegreat Jan 30 '14 at 02:16
  • 2
    If anyone's interested, I updated the code to stop playing the video when you click the "Close" button on a bootstrap 3 modal. $( "#MyModal-close" ).click(function() { var div = document.getElementById("MyModal-videoWrapper"); var iframe = div.getElementsByTagName("iframe")[0].contentWindow; iframe.postMessage('{"event":"command","func":"' + 'pauseVideo' + '","args":""}','*'); }); – Ryan Walton Sep 15 '14 at 15:33
  • 10
    Please note you have to add the `?enablejsapi=1` to the iframe embedding URL like so: `` or it won't work :) – dineth Dec 01 '14 at 01:19
  • This is actually the easiest to implement. – Kalpesh Panchal Oct 16 '15 at 19:09
23

Here's a jQuery take on RobW's answer for use hiding /pausing an iframe in a modal window:

    function toggleVideo(state) {
        if(state == 'hide'){
            $('#video-div').modal('hide');
            document.getElementById('video-iframe'+id).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
        }
        else {
            $('#video-div').modal('show');
            document.getElementById('video-iframe'+id).contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
        }
    }

The html elements referred to are the modal div itself (#video-div) calling the show / hide methods, and the iframe (#video-iframe) which has the video url as is src="" and has the suffix enablejsapi=1? which enables programmatic control of the player (ex. .

For more on the html see RobW's answer.

DrewT
  • 4,983
  • 2
  • 40
  • 53
  • 5
    What enhanced readability was changing the ? conditional to if / else but thanks for starting me out on this. I just felt I had something to valid add is all. – DrewT Dec 06 '13 at 00:17
16

Here is a simple jQuery snippet to pause all videos on the page based off of RobW's and DrewT's answers:

jQuery("iframe").each(function() {
  jQuery(this)[0].contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*')
});
quartarian
  • 557
  • 4
  • 10
  • if you don't want to use jQuery the code inside the 'each' function is the same after you de-reference the jQuery object. i.e. node.contentWindow. ... – mattdlockyer May 04 '16 at 16:11
  • How do I reverse this to play again when video is shown again? – Carl Papworth May 03 '17 at 11:46
  • Just replace "pauseVideo" with "playVideo". Example: https://jsfiddle.net/ora2kqzq/1/ – quartarian May 04 '17 at 18:23
  • That's no longer working... even when i try `{"event":"command","func":"playVideo","args":[],"id":1,"channel":"widget"}` after `{"event":"listening","id":1,"channel":"widget"}` which is what YT.Player iframe api is posting to youtube embed. – NoBugs Sep 08 '17 at 07:45
  • 1
    You must make sure to include `?enablejsapi=1` in your iframe source URL. This worked for me – mdurchholz Jan 10 '22 at 16:33
9

Hey an easy way is to simply set the src of the video to nothing, so that the video will desapear while it's hidden an then set the src back to the video you want when you click on the link that opens the video.. to do that simply set an id to the youtube iframe and call the src function using that id like this:

<script type="text/javascript">
function deleteVideo()
{
document.getElementById('VideoPlayer').src='';
}

function LoadVideo()
{
document.getElementById('VideoPlayer').src='http://www.youtube.com/embed/WHAT,EVER,YOUTUBE,VIDEO,YOU,WHANT';
}
</script>

<body>

<p onclick="LoadVideo()">LOAD VIDEO</P>
<p onclick="deleteVideo()">CLOSE</P>

<iframe id="VideoPlayer" width="853" height="480" src="http://www.youtube.com/WHAT,EVER,YOUTUBE,VIDEO,YOU,HAVE" frameborder="0" allowfullscreen></iframe>

</boby>
Paula
  • 91
  • 1
  • 1
  • 4
    Warning: Modifications to the `iframe`'s `src` with javascript will inadvertently push onto `window.history`, causing Back Button issues. – Jordan Arsenault May 01 '14 at 20:24
  • Thanks Jordan! Just started using this answer myself and wasn't aware of this behaviour. Better to know now than later on :) – MMachinegun Jul 04 '14 at 23:06
  • Fair warning to anybody trying this method: It may cause extremely noticeable lag if you are using this to switch between divs that contain iframe embeds for YouTube. Be careful. – Muhammad Abdul-Rahim Jul 16 '15 at 15:06
6

Since you need to set ?enablejsapi=true in the src of the iframe before you can use the playVideo / pauseVideo commands mentioned in other answers, it might be useful to add this programmatically via Javascript (especially if, eg. you want this behaviour to apply to videos embedded by other users who have just cut and paste a YouTube embed code). In that case, something like this might be useful:

function initVideos() {

  // Find all video iframes on the page:
  var iframes = $(".video").find("iframe");

  // For each of them:
  for (var i = 0; i < iframes.length; i++) {
    // If "enablejsapi" is not set on the iframe's src, set it:
    if (iframes[i].src.indexOf("enablejsapi") === -1) {
      // ...check whether there is already a query string or not:
      // (ie. whether to prefix "enablejsapi" with a "?" or an "&")
      var prefix = (iframes[i].src.indexOf("?") === -1) ? "?" : "&amp;";
      iframes[i].src += prefix + "enablejsapi=true";
    }
  }
}

...if you call this on document.ready then all iframes in a div with a class of "video" will have enablejsapi=true added to their source, which allows the playVideo / pauseVideo commands to work on them.

(nb. this example uses jQuery for that one line that sets var iframes, but the general approach should work just as well with pure Javascript if you're not using jQuery).

Community
  • 1
  • 1
Nick F
  • 9,781
  • 7
  • 75
  • 90
6

I wanted to share a solution I came up with using jQuery that works if you have multiple YouTube videos embedded on a single page. In my case, I have defined a modal popup for each video as follows:

<div id="videoModalXX">
...
    <button onclick="stopVideo(videoID);" type="button" class="close"></button>
    ...
    <iframe width="90%" height="400" src="//www.youtube-nocookie.com/embed/video_id?rel=0&enablejsapi=1&version=3" frameborder="0" allowfullscreen></iframe>
...
</div>

In this case, videoModalXX represents a unique id for the video. Then, the following function stops the video:

function stopVideo(id)
{
    $("#videoModal" + id + " iframe")[0].contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
}

I like this approach because it keeps the video paused where you left off in case you want to go back and continue watching later. It works well for me because it's looking for the iframe inside of the video modal with a specific id. No special YouTube element ID is required. Hopefully, someone will find this useful as well.

Poldon
  • 355
  • 2
  • 9
  • This worked great without a ton of code. I have multiple YT videos on the page and just showing a YT thumb and needed a stop/pause solution. And by changing pauseVideo to playVideo, I was able to start the video when it expanded to full column width – WebDude0482 Sep 07 '17 at 18:41
5

You can stop the video by calling the stopVideo() method on the YouTube player instance before hiding the div e.g.

player.stopVideo()

For more details see here: http://code.google.com/apis/youtube/js_api_reference.html#Playback_controls

david
  • 2,529
  • 1
  • 34
  • 50
4

RobW's way worked great for me. For people using jQuery here's a simplified version that I ended up using:

var iframe = $(video_player_div).find('iframe');

var src = $(iframe).attr('src');      

$(iframe).attr('src', '').attr('src', src);

In this example "video_player" is a parent div containing the iframe.

skribbz14
  • 845
  • 7
  • 7
2

just remove src of iframe

$('button.close').click(function(){
    $('iframe').attr('src','');;
});
Rakesh
  • 199
  • 1
  • 12
1

Rob W answer helped me figure out how to pause a video over iframe when a slider is hidden. Yet, I needed some modifications before I could get it to work. Here is snippet of my html:

<div class="flexslider" style="height: 330px;">
  <ul class="slides">
    <li class="post-64"><img src="http://localhost/.../Banner_image.jpg"></li>
    <li class="post-65><img  src="http://localhost/..../banner_image_2.jpg "></li>
    <li class="post-67 ">
        <div class="fluid-width-video-wrapper ">
            <iframe frameborder="0 " allowfullscreen=" " src="//www.youtube.com/embed/video-ID?enablejsapi=1 " id="fitvid831673 "></iframe>
        </div>
    </li>
  </ul>
</div>

Observe that this works on localhosts and also as Rob W mentioned "enablejsapi=1" was added to the end of the video URL.

Following is my JS file:

jQuery(document).ready(function($){
    jQuery(".flexslider").click(function (e) {
        setTimeout(checkiframe, 1000); //Checking the DOM if iframe is hidden. Timer is used to wait for 1 second before checking the DOM if its updated

    });
});

function checkiframe(){
    var iframe_flag =jQuery("iframe").is(":visible"); //Flagging if iFrame is Visible
    console.log(iframe_flag);
    var tooglePlay=0;
    if (iframe_flag) {                                //If Visible then AutoPlaying the Video
        tooglePlay=1;
        setTimeout(toogleVideo, 1000);                //Also using timeout here
    }
    if (!iframe_flag) {     
        tooglePlay =0;
        setTimeout(toogleVideo('hide'), 1000);  
    }   
}

function toogleVideo(state) {
    var div = document.getElementsByTagName("iframe")[0].contentWindow;
    func = state == 'hide' ? 'pauseVideo' : 'playVideo';
    div.postMessage('{"event":"command","func":"' + func + '","args":""}', '*');
}; 

Also, as a simpler example, check this out on JSFiddle

Fahim Hossain
  • 1,671
  • 13
  • 16
1

This approach requires jQuery. First, select your iframe:

var yourIframe = $('iframe#yourId');
//yourId or something to select your iframe.

Now you select button play/pause of this iframe and click it

$('button.ytp-play-button.ytp-button', yourIframe).click();

I hope it will help you.

Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
hong4rc
  • 3,999
  • 4
  • 21
  • 40
0

RobW's answers here and elsewhere were very helpful, but I found my needs to be much simpler. I've answered this elsewhere, but perhaps it will be useful here also.

I have a method where I form an HTML string to be loaded in a UIWebView:

NSString *urlString = [NSString stringWithFormat:@"https://www.youtube.com/embed/%@",videoID];

preparedHTML = [NSString stringWithFormat:@"<html><body style='background:none; text-align:center;'><script type='text/javascript' src='http://www.youtube.com/iframe_api'></script><script type='text/javascript'>var player; function onYouTubeIframeAPIReady(){player=new YT.Player('player')}</script><iframe id='player' class='youtube-player' type='text/html' width='%f' height='%f' src='%@?rel=0&showinfo=0&enablejsapi=1' style='text-align:center; border: 6px solid; border-radius:5px; background-color:transparent;' rel=nofollow allowfullscreen></iframe></body></html>", 628.0f, 352.0f, urlString];

You can ignore the styling stuff in the preparedHTML string. The important aspects are:

  • Using the API to create the "YT.player" object. At one point, I only had the video in the iFrame tag and that prevented me from referencing the "player" object later with JS.
  • I've seen a few examples on the web where the first script tag (the one with the iframe_api src tag) is omitted, but I definitely needed that to get this working.
  • Creating the "player" variable at the beginning of the API script. I have also seen some examples that have omitted that line.
  • Adding an id tag to the iFrame to be referenced in the API script. I almost forgot that part.
  • Adding "enablejsapi=1" to the end of the iFrame src tag. That hung me up for a while, as I initially had it as an attribute of the iFrame tag, which does not work/did not work for me.

When I need to pause the video, I just run this:

[webView stringByEvaluatingJavaScriptFromString:@"player.pauseVideo();"];

Hope that helps!

Community
  • 1
  • 1
Brian
  • 301
  • 3
  • 10
  • In case you're wondering why no upvotes, it's because that's not javascript so not useful for the the OP's use case which is an iframe referencing a youtube embed url not an iOS app. – Vroo Jan 03 '15 at 00:33
  • @Vroo Yeah, I get that. Just wanted to leave this answer here in case another iOS person came here and found this question as I did. – Brian Jan 04 '15 at 17:14
0

This is working fine to me with YT player

 createPlayer(): void {
  return new window['YT'].Player(this.youtube.playerId, {
  height: this.youtube.playerHeight,
  width: this.youtube.playerWidth,
  playerVars: {
    rel: 0,
    showinfo: 0
  }
});
}

this.youtube.player.pauseVideo();

HuyLe
  • 1,870
  • 1
  • 14
  • 11
0

A more concise, elegant, and secure answer: add “?enablejsapi=1” to the end of the video URL, then construct and stringify an ordinary object representing the pause command:

const YouTube_pause_video_command_JSON = JSON.stringify(Object.create(null, {
    "event": {
        "value": "command",
        "enumerable": true
    },
    "func": {
        "value": "pauseVideo",
        "enumerable": true
    }
}));

Use the Window.postMessage method to send the resulting JSON string to the embedded video document:

// |iframe_element| is defined elsewhere.
const video_URL = iframe_element.getAttributeNS(null, "src");
iframe_element.contentWindow.postMessage(YouTube_pause_video_command_JSON, video_URL);

Make sure you specify the video URL for the Window.postMessage method’s targetOrigin argument to ensure that your messages won’t be sent to any unintended recipient.

Patrick Dark
  • 2,187
  • 1
  • 20
  • 23