handling multiple youtube videos - javascript

I have three youtube videos that I want to stop when the user click on a link link the page.
this is my code
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var youtubePlayer1;
var youtubePlayer2;
var youtubePlayer3;
function onYouTubeIframeAPIReady() {
youtubePlayer1 = new YT.Player('firstPlayer', {
});
youtubePlayer2 = new YT.Player('secondPlayer', {
});
youtubePlayer3 = new YT.Player('thirdPlayer', {
});
}
function stopVideo() {
if (youtubePlayer1 != null) {
youtubePlayer1.stopVideo();
}
if (youtubePlayer2 != null) {
youtubePlayer2.stopVideo();
}
if (youtubePlayer3 != null) {
youtubePlayer3.stopVideo();
}
}
This is the html code
<div id="blog">
<!--///////////// UN ORDERED LIST /////////////-->
<ul>
<!--///////////// LIST /////////////-->
<li>
<!-- iframe -->
<h3>
<strong>להקת קולות - בהרקדה חסידית...</strong></h3>
<br />
<iframe id="firstPlayer" width="800" height="485" src="http://www.youtube.com/embed/F0eR1KFkt58"
style="border:0" ></iframe>
<br />
<br />
<img src="images/bg3.PNG" alt="" /><p>
<span>תאור הוידאו: </span>טקסט אודות הוידאו, תאריך</p>
</li>
<!--///////////// SECOND IMAGE /////////////-->
<li>
<!-- iframe -->
<h3>
<strong>להקת קולות - בהרקדה ישראלית מוטרפת...</strong></h3>
<br />
<iframe id="secondPlayer" width="800" height="485" src="http://www.youtube.com/embed/mPTX4guU1W8"
style="border:0" ></iframe>
<br />
<br />
<img src="images/bg3.PNG" alt="" /><p>
<span>תאור הוידאו: </span>טקסט אודות הוידאו, תאריך</p>
</li>
<!--///////////// THIRD IMAGE /////////////-->
<li>
<!-- iframe -->
<h3>
<strong>להקת קולות - בואי בשלום...</strong></h3>
<br />
<iframe id="thirdPlayer" width="800" height="485" src="http://www.youtube.com/embed/E-_ONZOcScU"
style="border:0"></iframe>
<br />
<br />
<img src="images/bg3.PNG" alt="" /><p>
<span>תאור הוידאו: </span>טקסט אודות הוידאו, תאריך</p>
</li>
</ul>
</div>
when the user click on the link it calls the stopVideo function that cycle through all the players and stop them.
for some reason I can get it to work only on youtubePlayer2 object what am I doing wrong here?
Forgot to mention, when I debug the app using the chrome debugger I can see the the objects are defined and that the function is called.

I think that in this way works:
http://jsfiddle.net/ZLMF8/3/
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/swfobject/2/swfobject.js"></script></head>
<body>
<div id="ytplayer1">
<p>You will need Flash 8 or better to view this content.</p>
</div>
<div id="ytplayer2">
<p>You will need Flash 8 or better to view this content.</p>
</div>
<div id="ytplayer3">
<p>You will need Flash 8 or better to view this content.</p>
</div>
<script type="text/javascript">
var params = { allowScriptAccess: "always" };
swfobject.embedSWF("http://www.youtube.com/v/F0eR1KFkt58&enablejsapi=1&playerapiid=ytplayer1", "ytplayer1", "425", "365", "8", null, null, params);
swfobject.embedSWF("http://www.youtube.com/v/mPTX4guU1W8&enablejsapi=1&playerapiid=ytplayer2", "ytplayer2", "425", "365", "8", null, null, params);
swfobject.embedSWF("http://www.youtube.com/v/E-_ONZOcScU&enablejsapi=1&playerapiid=ytplayer3", "ytplayer3", "425", "365", "8", null, null, params);
function stop() {
if (ytplayer1) {
ytplayer1.stopVideo();
}
if (ytplayer2) {
ytplayer2.stopVideo();
}
if (ytplayer3) {
ytplayer3.stopVideo();
}
}​
</script>
Stop
</body>
</html>​

This code sample should work without issue, and in my testing it worked without flaw. Try making sure the script tag is added at the bottom of the page. This will help insure that the iframes are loaded by the time you make calls to them. Also try out http://www.youtube.com/html5 to see if that has a more reliable experience.

I don't see the need for the if statement if your code just runs on when not being able to find the youtubeplayer, but I once solved a problem similar by adding a else statement that made sure something would happen - which may explain why the above was only happening every now and then.
It only takes a little copy and paste.
function stopVideo() {
if (youtubePlayer1 != null) {
youtubePlayer1.stopVideo();
}
else {
youtubePlayer1.stopVideo();
}
if (youtubePlayer2 != null) {
youtubePlayer2.stopVideo();
}
else {
youtubePlayer2.stopVideo();
}
if (youtubePlayer3 != null) {
youtubePlayer3.stopVideo();
}
else {
youtubePlayer3.stopVideo();
}
}

Try this, its worked fine.
Note http:// is missing in src, because stackoverflow shows an error while posting with src. so correct it and test.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" type="text/javascript"></script>
tag.src = "//www.youtube.com/iframe_api";
Full working code
<!DOCTYPE HTML>
<html>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" type="text/javascript"></script>
<body>
<div id="firstPlayer"></div>
<div id="secondPlayer"></div>
<div id="thirdPlayer"></div>
<script>
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var youtubePlayer1;
var youtubePlayer2;
var youtubePlayer3;
function onYouTubeIframeAPIReady() {
youtubePlayer1 = new YT.Player('firstPlayer',{
height: '240',
width: '320',
videoId: 'F0eR1KFkt58',
events: {
'onReady': onPlayerReady1
}
});
youtubePlayer2 = new YT.Player('secondPlayer', {
height: '240',
width: '320',
videoId: 'mPTX4guU1W8',
events: {
'onReady': onPlayerReady2
}
});
youtubePlayer3 = new YT.Player('thirdPlayer', {
height: '240',
width: '320',
videoId: 'E-_ONZOcScU',
events: {
'onReady': onPlayerReady3
}
});
}
function onPlayerReady1(event) {
event.target.playVideo();
$('a').click(function(e) {
youtubePlayer1.stopVideo();
e.preventDefault();
});
}
function onPlayerReady2(event) {
event.target.playVideo();
$('a').click(function(e) {
youtubePlayer2.stopVideo();
e.preventDefault();
});
}
function onPlayerReady3(event) {
event.target.playVideo();
$('a').click(function(e) {
youtubePlayer3.stopVideo();
e.preventDefault();
});
}
</script>
<a>Stop</a>
</body>
</html>

Mohamed Navas' answer (first answer) helped me to come up with this:
<br>
<button id="pause">Pause</button>
<br>
<br>
<div id="firstPlayer"></div>
<div id="secondPlayer"></div>
<div id="thirdPlayer"></div>
<script>
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var youtubePlayer1;
var youtubePlayer2;
var youtubePlayer3;
function onYouTubeIframeAPIReady() {
youtubePlayer1 = new YT.Player('firstPlayer',{
height: '240',
width: '320',
videoId: 'qV9HxRU4ozY',
events: {
'onReady': onPlayerReady
}
});
youtubePlayer2 = new YT.Player('secondPlayer', {
height: '240',
width: '320',
videoId: 'nBRpWJ0QUH0',
events: {
'onReady': onPlayerReady
}
});
youtubePlayer3 = new YT.Player('thirdPlayer', {
height: '240',
width: '320',
videoId: 'E-_ONZOcScU',
events: {
'onReady': onPlayerReady
}
});
}
function onPlayerReady(event) {
document.getElementById('pause').onclick = function() {
youtubePlayer1.pauseVideo();
youtubePlayer2.pauseVideo();
youtubePlayer3.pauseVideo();
e.preventDefault();
};
};
</script>
https://jsfiddle.net/tonhaoln/ancz2vkn/

Related

YouTube Player API - Seek and then play

I'm having an issue when trying to use .seekTo() with the YouTube Player API. The first time I set the .seekTo() the video will correctly seek to the value (e.g. 4 seconds) and then play [without me issuing .playVideo()]. The video is stopped when I call .seekTo() the 2nd time and the video plays from the start. I want to be able to start the video again from the seek location.
<!DOCTYPE html>
<html>
<head>
<scriptm src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
<div id="player"></div>
<div>
<button id="btnSeek" data-seek="30.7">Seek 30</button>
<button id="btnSeek" data-seek="60">Seek 60</button>
<button id="btnSeek" data-seek="90">Seek 90</button>
<button id="btnSeek" data-seek="180">Seek 180</button>
</div>
<script>
$.getScript('//www.youtube.com/iframe_api');
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: '-HjpL-Ns6_A',
playerVars: { 'start': 159, 'autoplay': 1, 'controls': 1, 'showinfo': 0, 'rel': 0 },
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange,
}
});
}
var done = false;
function onPlayerStateChange(evt)
{
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function onPlayerReady(evt) {
// doesn't work here
// player.seekTo(30);
// lets make ure we have a function
//alert("typeof(player.SeekTo) = " + typeof(player.seekTo));
}
function stopVideo() {
player.stopVideo();
}
$(function() {
$(document).on('click', '#btnSeek', function() {
if(player.getCurrentTime() == player.getDuration())
{
player.playVideo();
}
player.seekTo($(this).data('seek'), true);
});
});
</script>
</body>

Multiple instances of YouTube player inside loop

I have the following code, which works - but the part I can't figure out is how to grab the index in the onReady event. The result is 2,2 instead of 0,1 which I would expect - why?
Codepen
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var players = [];
var playerEl = document.querySelectorAll('.ytplayer');
function onYouTubeIframeAPIReady() {
for (var i = 0; i < playerEl.length; i++) {
players[i] = new YT.Player(playerEl[i], {
events: {
'onReady': () => { console.log('index: '+i) } // why doesn't this return 0,1 ??
}
});
}
}
<iframe class="video ytplayer" width="100%" height="390" type="text/html" src="https://www.youtube.com/embed/ScMzIvxBSi4?controls=0&t=31s&loop=1&playlist=ScMzIvxBSi4&showinfo=0&rel=0&enablejsapi=1" frameborder="0" allowfullscreen></iframe>
<iframe class="video ytplayer" width="100%" height="390" type="text/html" src="https://www.youtube.com/embed/iGpuQ0ioPrM?controls=0&t=31s&loop=1&playlist=iGpuQ0ioPrM&showinfo=0&rel=0&enablejsapi=1" frameborder="0" allowfullscreen></iframe>
I managed to solve it using the following code. The mistake I was making was I was trying to store a variable inside an event. The event is async and doesn't know that it's inside a loop - at least I think that's it, please correct me if I'm wrong.
Codepen working
function onYouTubeIframeAPIReady() {
document.querySelectorAll('.ytplayer').forEach((item) => {
new YT.Player(item, {
events: {
'onReady': (event) => {
event.target.playVideo();
event.target.mute();
}
}
})
})
}

Youtube Video Autoplay in popup

I've made a popup and placed a youtube video in it. I set video to autoplay. But the problem is video plays when i open the page. It is auto play in global and i want it to autoplay when popup shows. I did not find any solution for it.
Currently, It playing like i have background ghost saying something.
Can anyone help?
Video Html
<iframe width="800" height="315" src="http://www.youtube.com/embed/?wmode=opaque&autoplay=1&rel=0&color=white" frameborder="0"></iframe><img alt="" class="watermark" src="https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQHcbyVSjHQlwCy3tYqOyLwSWDO4tblhxTVVjKV5R0PtFsPy9TwfA" /></div>
</div>
Calling popup
<img src="kaow.png"/>
</div>
Popup Content
<div id="video_pop" class="reveal-modal medium">
<a class="close-reveal-modal"></a>
<div>
<iframe width="800" height="315" src="http://www.youtube.com/embed/?wmode=opaque&autoplay=1&rel=0&color=white" frameborder="0"></iframe><img alt="" class="watermark" src="https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQHcbyVSjHQlwCy3tYqOyLwSWDO4tblhxTVVjKV5R0PtFsPy9TwfA" /></div>
</div>
JS
Foundation.libs.reveal = {
name: "reveal",
version: "4.2.2",
locked: !1,
settings: {
animation: "fadeAndPop",
animationSpeed: 250,
closeOnBackgroundClick: !0,
closeOnEsc: !0,
dismissModalClass: "close-reveal-modal",
bgClass: "reveal-modal-bg",
open: function() {},
opened: function() {},
close: function() {},
closed: function() {},
bg: a(".reveal-modal-bg"),
css: {
open: {
opacity: 0,
visibility: "visible",
display: "block"
},
close: {
opacity: 1,
visibility: "hidden",
display: "none"
}
}
},
init: function(b, c, d) {
return Foundation.inherit(this, "data_options delay"), "object" == typeof c ? a.extend(!0, this.settings, c) : "undefined" != typeof d && a.extend(!0, this.settings, d),
"string" != typeof c ? (this.events(), this.settings.init) : this[c].call(this, d);
},
events: function() {
var b = this;
return a(this.scope).off(".fndtn.reveal").on("click.fndtn.reveal", "[data-reveal-id]", function(c) {
c.preventDefault();
if (!b.locked) {
var d = a(this), e = d.data("reveal-ajax");
b.locked = !0;
if ("undefined" == typeof e) b.open.call(b, d); else {
var f = e === !0 ? d.attr("href") : e;
b.open.call(b, d, {
url: f
});
}
}
}).on("click.fndtn.reveal", this.close_targets(), function(c) {
c.preventDefault();
if (!b.locked) {
var d = a.extend({}, b.settings, b.data_options(a(".reveal-modal.open")));
if (a(c.target)[0] === a("." + d.bgClass)[0] && !d.closeOnBackgroundClick) return;
b.locked = !0, b.close.call(b, a(this).closest(".reveal-modal"));
}
}).on("open.fndtn.reveal", ".reveal-modal", this.settings.open).on("opened.fndtn.reveal", ".reveal-modal", this.settings.opened).on("opened.fndtn.reveal", ".reveal-modal", this.open_video).on("close.fndtn.reveal", ".reveal-modal", this.settings.close).on("closed.fndtn.reveal", ".reveal-modal", this.settings.closed).on("closed.fndtn.reveal", ".reveal-modal", this.close_video),
a("body").bind("keyup.reveal", function(c) {
var d = a(".reveal-modal.open"), e = a.extend({}, b.settings, b.data_options(d));
27 === c.which && e.closeOnEsc && d.foundation("reveal", "close");
}), !0;
},
open: function(b, c) {
if (b) if ("undefined" != typeof b.selector) var d = a("#" + b.data("reveal-id")); else {
var d = a(this.scope);
c = b;
} else var d = a(this.scope);
if (!d.hasClass("open")) {
var e = a(".reveal-modal.open");
"undefined" == typeof d.data("css-top") && d.data("css-top", parseInt(d.css("top"), 10)).data("offset", this.cache_offset(d)),
d.trigger("open"), e.length < 1 && this.toggle_bg(d);
if ("undefined" == typeof c || !c.url) this.hide(e, this.settings.css.close), this.show(d, this.settings.css.open); else {
var f = this, g = "undefined" != typeof c.success ? c.success : null;
a.extend(c, {
success: function(b, c, h) {
a.isFunction(g) && g(b, c, h), d.html(b), a(d).foundation("section", "reflow"),
f.hide(e, f.settings.css.close), f.show(d, f.settings.css.open);
}
}), a.ajax(c);
}
}
},
close: function(b) {
var b = b && b.length ? b : a(this.scope), c = a(".reveal-modal.open");
c.length > 0 && (this.locked = !0, b.trigger("close"), this.toggle_bg(b), this.hide(c, this.settings.css.close));
},
close_targets: function() {
var a = "." + this.settings.dismissModalClass;
return this.settings.closeOnBackgroundClick ? a + ", ." + this.settings.bgClass : a;
},
toggle_bg: function(b) {
0 === a(".reveal-modal-bg").length && (this.settings.bg = a("<div />", {
"class": this.settings.bgClass
}).appendTo("body")), this.settings.bg.filter(":visible").length > 0 ? this.hide(this.settings.bg) : this.show(this.settings.bg);
},
EDITED:
I am using Foundation 5 Reveal Model for popup: http://foundation.zurb.com/docs/components/reveal.html
I think you want something like that :
LIVE EXAMPLE
Basically i use the API Javascript to add actions play and pause to the video.
And i use default function of Foundation to add an event when to the player.
HTML
Click Me For A Modal
<div id="myModal" class="reveal-modal" data-reveal>
<h2>Awesome</h2>
<div id="player"></div>
<a class="close-reveal-modal">×</a>
</div>
JS
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '315',
width: '560',
videoId: 'l-gQLqv9f4o',
events: {
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING) {
//player is playing
} else {
//player is paused
}
}
function stopVideo() {
player.stopVideo();
}
function playVideo() {
player.playVideo();
}
function pauseVideo() {
player.pauseVideo();
}
$(document).on('opened.fndtn.reveal', '[data-reveal]', function () {
playVideo();
});
$(document).on('closed.fndtn.reveal', '[data-reveal]', function () {
pauseVideo();
});
From the YouTube JavaScript Player API Reference:
The JavaScript API allows users to control the YouTube chromeless or
embedded video players via JavaScript. Calls can be made to play,
pause, seek to a certain time in a video, set the volume, mute the
player, and other useful functions.
You can use the API's player.playVideo(), player.pauseVideo() and player.stopVideo() method.
So, Ive read a bunch of different threads on this and most of what Ive seen is pretty complicated. I went a much more simple route.
$('.reveal-overlay').click(function(e){
var loc = document.getElementById('myFrame').src;
var stoploc = loc.replace("?autoplay=1", "");
document.getElementById('myFrame').setAttribute('src', stoploc);
});
$('.playVideo').click(function(e){
var loc = document.getElementById('myFrame').src;
var autoloc = loc + "?autoplay=1";
document.getElementById('myFrame').setAttribute('src', autoloc);
});
This will basically just append ?autoplay=1 to a YouTube video once the modal is opened. The class .playVideo is on whatever button youre using to open your modal window.
The class .reveal-overlay is created by Foundation. So when the overlay is clicked it removes any ?autoplay=1 from the video url.
Hope this helps anyone running into this problem. It's simple and should work for multiple different videos, plus, if someone has js turned off, it won't play anything in the background.
One more thing, the video you load should be a regular non-autoplay video. This will turn it into an autoplay after clicked ony and return it to non-autoplay when closed.
Thanks to #Jarod Means script! It works and I uses it since it only requires jQuery (Simple solution = Great solution). But I developed it for multiple video clips, which is great in slideshows, as an example or whenever you need this solution for more then one clip in the same dom. I also made it so it is completely in jQuery.
Just posting it so you can use it as you wish.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<meta charset="utf-8">
<title>Youtube-player test</title>
<style>
.youtube-player iframe {
display: none;
}
.youtube-player.active iframe {
display: block;
}
</style>
</head>
<body>
<div class="youtube-player">
<iframe width="560" height="315" src="https://www.youtube.com/embed/XzXjuDM_Z54" frameborder="0" allowfullscreen></iframe>
Open window
Close window
</div>
<div class="youtube-player">
<iframe width="560" height="315" src="https://www.youtube.com/embed/l2EYyzXJIdE" frameborder="0" allowfullscreen></iframe>
Open window
Close window
</div>
<script>
jQuery('.youtube-player').each(function(){
jQuery(this).on('click', '.youtube-link-start', function(){
jQuery(this).parent().addClass('active');
var loc = $(this).siblings('iframe').attr('src');
var startloc = loc + "?autoplay=1";
$(this).siblings('iframe').attr('src', startloc);
});
jQuery(this).on('click', '.youtube-link-stop', function(){
jQuery(this).parent().removeClass('active');
var loc = $(this).siblings('iframe').attr('src');
var stoploc = loc.replace("?autoplay=1", "");
$(this).siblings('iframe').attr('src', stoploc);
});
});
</script>
</body>
</html>
I guess you can keep on changing/developing this with html, css and jQuery to whatever fit your needs. :)

Binding YouTube Video to Div Element from Seperate JS file

I have this problem embedding YouTube video in a PhoneJS single-page mobile application. In PhoneJS, the JS scripts are defined in a different file. So I defined the HTML div like this:
<div id="player"></div>
Now in the JS file, I did this:
function getVideo() {
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player(playerDiv, {
height: '250',
width: '444',
videoId: sIFYPQjYhv8
});
}
}
When I run and view the debugger, the call is made to Youtube and response is received, but it is not displayed on the view.
Ok since I am using KnockoutJS binding, I modified the div in the html view like this:
<iframe id="player" type="text/html" width="444" height="250" frameborder="0" data-bind="attr: { src: src }"></iframe>
And then pass in the src video id thus:
src: ko.observable('http://www.youtube.com/embed/' + sIFYPQjYhv8 + '?autoplay=1')
In this case however, in the debugger, the call is not even made to Youtube. Nothing just happens. Actually I prefer to use the API call instead of the second approach.
Any suggestions on how to make the first approach work? I mean using the API call?
EDIT
Just want to mention that when I add the code below in the view, the video is streamed alright.
<h1>Video</h1>
<div id="player"></div>
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player(playerDiv, {
height: '250',
width: '444',
videoId: 'sIFYPQjYhv8'
});
}
</script>
I think the easiest way to do this is to use a custom binding handler with a flag set from the onYouTubeIFrameAPIReady callback
Sample jsFiddle
ko.bindingHandlers['player'] = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// Check if global script and function is declared.
if ( !document.getElementById('playerScript') ) {
// Create script
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var playerDiv = document.getElementById('player');
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// Create global function that their API calls back
window.playerReady = ko.observable(false);
window.onYouTubeIframeAPIReady = function() {
window.playerReady(true);
};
}
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor(),
id = value.id(),
height = ko.unwrap(value.height) || '250',
width = ko.unwrap(value.width) || '444'
;
if ( !value.id()) {
return;
}
if ( !window.playerReady() ) {
// YT hasn't invoked global callback. Subscribe to update
var subscription;
subscription = window.playerReady.subscribe( function(newValue) {
if ( newValue ) {
subscription.dispose();
// Just get this binding to fire again
value.id.notifySubscribers(value.id());
}
});
} else {
var player = new YT.Player( element, {
height: height,
width: width,
videoId: id
});
}
},
}
Now change your player div to
<div data-bind="player: { id: id, height: height, width: width }"></div>
Finally bind
var vm = {
id: 'sIFYPQjYhv8',
height: '250',
width: '444'
};
ko.applyBindings( vm )
EDIT
To remove the reliance on window, put your script tag that adds the new script element back, tweek as below, modify their callback and use a setTimeout instead of the "playerReady" observable
HTML Script
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
tag.setAttribute('id', 'playerScript');
tag.setAttribute('data-ready', 'false');
...
function onYouTubeIframeAPIReady = function() {
document.getElementById('playerScript').setAttribute('data-ready', 'true');
};
Player Binding
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor(),
id = value.id(),
height = ko.unwrap(value.height) || '250',
width = ko.unwrap(value.width) || '444',
playerScript = document.getElementById('playerScript')
;
if ( !value.id()) {
return;
}
if ( !playerScript || playerScript.getAttribute('data-ready') !== 'true' ) ) {
// YT hasn't invoked global callback.
setTimeout( function() {
value.id.notifySubscribers(value.id());
}, 50);
} else {
var player = new YT.Player( element, {
height: height,
width: width,
videoId: id
});
}
}

Using an array in Jquery

I'm not so experienced with Javascript and I have been struggling with this one pretty much all day.
I'm using Jquery to create and array of the ids of embedded youtube videos:
$(function() {
$('li').on("click",function(){
alert($(this).attr('data-pile'));
var pilename = $(this).attr('data-pile');
var videoIDs = [];
$("li[data-pile='"+pilename+"']").each(function(index){
videoIDs.push($(this).attr('id'));
});
$.each(videoIDs,function(){
});
});
});
And I need to use the array in this JS:
<script src="//www.youtube.com/iframe_api"></script>
<script>
/**
* Put your video IDs in this array
*/
var videoIDs = [
//my array of Ids here
];
var player, currentVideoId = 0;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '350',
width: '425',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(event) {
event.target.loadVideoById(videoIDs[currentVideoId]);
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED) {
currentVideoId++;
if (currentVideoId < videoIDs.length) {
player.loadVideoById(videoIDs[currentVideoId]);
}
}
}
</script>
In each div where embedded videos are I'm applying an id with same id as video.
How should I make the two scripts work?
I'll really appreciate if someone can point me in the right direction.
You're declaring your videoIDs array twice, once in your click events and again in your second
script.
The one inside your click events is local to that function whereas the other one is global. Javascript has function scope, so that click event one gets discarded once that function ends.
If you remove the one inside your click events, I believe it should work. You should also remove the $.each... as I don't think it's going to help (you're trying to make a playlist, right?).
It should be noted that it's considered bad practice to pollute the global namespace by using global variables. If this is all the code you have on your page, it's probably not an issue.
Try doing it this way: add a custom listener after "click" event. Didn't check your array forming section, tested with a custom array, hope you won't have issues with it.
<script>
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '350',
width: '425',
});
}
$(function(){
$(document.body).on("click",".play", function(){
player.stopVideo();
var pilename = $(this).attr('data-pile');
var videoIDs = [];
$("li[data-pile='"+pilename+"']").each(function(index){
videoIDs.push($(this).attr('id'));
});
if(videoIDs.length > 0){
currentVideoId = 0;
player.loadVideoById(videoIDs[0]);
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED) {
currentVideoId++;
if (currentVideoId < videoIDs.length) {
player.loadVideoById(videoIDs[currentVideoId]);
}
}
}
player.addEventListener("onStateChange", onPlayerStateChange)
player.playVideo();
}
});
});
</script>

Categories

Resources