I'm trying to load YouTube's iframe API. So far, all I'm trying to do is make and load the player. It seems to load the API, but then not recognize "YT.Player()" as a constructor. The exact error I'm getting at that line, in the chrome js console, is:
Uncaught TypeError: undefined is not a function
So... What in the world am I doing wrong? I've thrown console.log statements all over this thing, and tried rewriting it in a few ways. I've tried copying the api into a local file. I've tried loading it with regular script tags. I've tried loading it with the wacky DOM Modification they used in the api reference at https://developers.google.com/youtube/iframe_api_reference. I'm pretty sure the code below should work:
function youtubeAPIReady(script, textStatus, jqXHR)
{
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'CxTtN0dCDaY'
});
}
function readyFunction()
{
$.getScript("https://www.youtube.com/iframe_api", youtubeAPIReady);
}
jQuery(document).ready(readyFunction);
Any help?
You can borrow the technique used in YouTube Direct Lite to defer loading the JavaScript until it's explicitly needed:
var player = {
playVideo: function(container, videoId) {
if (typeof(YT) == 'undefined' || typeof(YT.Player) == 'undefined') {
window.onYouTubeIframeAPIReady = function() {
player.loadPlayer(container, videoId);
};
$.getScript('//www.youtube.com/iframe_api');
} else {
player.loadPlayer(container, videoId);
}
},
loadPlayer: function(container, videoId) {
new YT.Player(container, {
videoId: videoId,
width: 356,
height: 200,
playerVars: {
autoplay: 1,
controls: 0,
modestbranding: 1,
rel: 0,
showInfo: 0
}
});
}
};
poor man's solution, but ...
function readyYoutube(){
if((typeof YT !== "undefined") && YT && YT.Player){
player = new YT.Player('player', {
...
});
}else{
setTimeout(readyYoutube, 100);
}
}
Quote from http://api.jquery.com/jQuery.getScript/
The callback is fired once the script has been loaded but not
necessarily executed.
The API probably hasn't run by the time you call YT.Player()
I can't speak for the jQuery solution, but try using the stock standard javascript. In any case you won't have to wait for the document to be loaded (this code should sit outside $(document).ready())
// Load the YouTube API asynchronously
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// Create the player object when API is ready
var player;
window.onYouTubeIframeAPIReady = function () {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'CxYyN0dCDaY'
});
};
I've solved this issue by combining approaches of Simon and user151496.
The code:
<script>
// load API
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// define player
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '360',
width: '640'
});
}
$(function () {
// load video and add event listeners
function loadVideo(id, start, end) {
// check if player is defined
if ((typeof player !== "undefined")) {
// listener for player state change
player.addEventListener('onStateChange', function (event) {
if (event.data == YT.PlayerState.ENDED) {
// do something
}
});
// listener if player is ready (including methods, like loadVideoById
player.addEventListener('onReady', function(event){
event.target.loadVideoById({
videoId: id,
startSeconds: start,
endSeconds: end
});
// pause player (my specific needs)
event.target.pauseVideo();
});
}
// if player is not defined, wait and try again
else {
setTimeout(loadVideo, 100, id, start, end);
}
}
// somewhere in the code
loadVideo('xxxxxxxx', 0, 3);
player.playVideo();
});
</script>
Remove the add block from your browser and try again. Its worked for me.
Related
When $('#myModal').on('show.bs.modal' gets called. I get this:
TypeError: player.loadVideoById is not a function. (In 'player.loadVideoById(x)', 'player.loadVideoById' is undefined)
https://jsfiddle.net/rdbj3ty1/5/
In JS Fiddle the code works, but when I add it to my code base, it stops working. I have a lot of other js code and CSS code that it must be interfering with. Is there a way to prevent the interference? Maybe wrap my js code with a block or add more specific references? Is namespacing the issue? If so, how do I do that?
I don't really know what to try. I have spent 2 days on this and getting nowhere.
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);
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'novideoid',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
$('.open-popup').click(function() {
event.target.playVideo();
});
$('.close-popup').click(function(e) {
player.stopVideo();
});
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if(event.data === 0) {
$('.close.close-popup').click();
}
}
function stopVideo() {
player.stopVideo();
}
$(function () {
onYouTubeIframeAPIReady();
$('#myModal').on('show.bs.modal', function(e) {
var videoId = $(e.relatedTarget).data('video-id');
var x = new String(videoId);
player.loadVideoById(x);
});
});
In one of my modals I want to display a youtube video. Which one (which ID) depends on which button is used to open the model.
<button class='yt-play' data-yt='xxxxxx'>Play video</button>
In my javascript file I'm using the YT player-api to generate an iframe; i followed the Getting started on google developers.
So In the modal I added an <div id='player'></div> and This is my included javascript:
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 player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
videoId: '5ulO97zuVF0', //- just a temporary id
});
}
// on document ready do some jQuery things,
// like adding an event handler to the button.
$(document).ready(function (){
$('.yt-play').click(function(ev){
ev.preventDefault();
var videoid = $(this).data('yt');
player.loadVideoById(videoid);
$('#yt-player').modal('show');
player.playVideo();
});
});
The click-handler on yt-play should load the video by means of player.loadVideoById() as stated here in the documentation.
But somehow I get an javascript error: TypeError: player.loadVideoById is not a function
If I dump the player-object in the console I'm getting a nice player object; which holds amongst many others the loadVideoById function. At least it looks like it:
What's the reason the new video is not loaded?
It's possibly because the "loadVideoById" is not yet available.
You must construct your YT.Player Object with an events object, and include an "onReady" Event callback.
Then in your "onReady" callback function you bind your Button click event.
function onPlayerReady() {
$('.yt-play').click(function(ev){
ev.preventDefault();
var videoid = $(this).data('yt');
// player.loadVideoByID is now available as a function
player.loadVideoById(videoid);
$('#yt-player').modal('show');
player.playVideo();
});
}
player = new YT.Player('player', {
videoId: '5ulO97zuVF0', //- just a temporary id,
events:{
“onReady”: onPlayerReady
}
});
See the events section in the docs for more:
https://developers.google.com/youtube/iframe_api_reference#Events
add div element in html document
initial YT to global object in onYouTubeIframeAPIReady function
call YT object in your function
The code:
<script>
// load API
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// define player
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '360',
width: '640'
});
}
$(function () {
// load video and add event listeners
function loadVideo(id, start, end) {
// check if player is defined
if ((typeof player !== "undefined")) {
// listener for player state change
player.addEventListener('onStateChange', function (event) {
if (event.data == YT.PlayerState.ENDED) {
// do something
}
});
// listener if player is ready (including methods, like loadVideoById
player.addEventListener('onReady', function(event){
event.target.loadVideoById({
videoId: id,
startSeconds: start,
endSeconds: end
});
// pause player (my specific needs)
event.target.pauseVideo();
});
}
// if player is not defined, wait and try again
else {
setTimeout(loadVideo, 100, id, start, end);
}
}
// somewhere in the code
loadVideo('xxxxxxxx', 0, 3);
player.playVideo();
});
</script>
The other answers don't clarify the issue.
The YouTube api is confusing for sure! This is because the YT.Player constructer returns a dom reference to the iframe of the youtube player not to the YT player object.
In order to get a reference to the YT player we need to listen to the onReady event.
var ytPlayer;
var videoIframe = new YT.Player('player', {
videoId: 'xxxxxxx', // youtube video id
playerVars: {
'autoplay': 0,
'rel': 0,
'showinfo': 0
},
events: {
'onStateChange': onPlayerStateChange,
'onReady': function (ev) {
ytPlayer = ev.target;
}
}
});
Only 6 years late to the party, I have the solution.
The issue is that the YouTube API doesn't like the DOM shuffling Foundation does when it opens a modal.
The only way to achieve this is to create the YouTube player after opening the modal:
function play_video(ytid) {
modal = new Foundation.Reveal($('#yt_modal'),{});
modal.open();
ytplayer = new YT.Player('ytplayer', {
videoId: ytid,
height: '390',
width: '640',
playerVars: {
'playsinline': 1
},
events: {
'onReady': whatever()
}
});
}
This assumes
<div id="ytplayer"></div>
is inside your Foundation modal.
Oh and you'll need to remove the iframe each time else YouTube API just looks for the old iframe (which isn't where it expects, cos the modal is closed and the DOM has changed):
$(document).on('closed.zf.reveal', function(e) {
switch($(e.target).prop('id')) {
case 'yt_modal':
ytplayer.destroy();
break;
}
});
And regarding #Tosh's answer about the API returning a reference to the iframe not the player is not true as far as I can determine by comparing it to what's returned by onReady(ev.target) - they appear identical (so don't go down that blind alley like I did!)
i need to show a popup when youtube video finish it works fine for the alert() but when i tried to make magnific popup instead if the alert it dosen't work here is my code
<script>
// 2. This code loads the IFrame Player API code asynchronously.
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: '600',
width: '600',
videoId: 'id',
playerVars: { 'autoplay':"0", 'controls':"1" },
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
var playerReady = false;
function onPlayerReady(event) {
playerReady = true;
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED ) {
$.magnificPopup.open({
items: {
src: 'mylink to the pic'
},
type: 'image'
// You may add options here, they're exactly the same as for $.fn.magnificPopup call
// Note that some settings that rely on click event (like disableOn or midClick) will not work here
}, 0); }
}
</script>
so I'm loading a youtube playlist using:
event.target.loadPlaylist(videoIds);
and I'm getting this error:
The weird part is the playlist loads fine for about one second,
and then breaks giving me that error.
sorry heres the surrounding code:
window.tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
window.firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
// window.player;
window.onYouTubeIframeAPIReady = function() {
player = new YT.Player('player', {
height: '480',
width: '853',
playerVars: {
controls: 1,
modestbranding: 1,
playsinline: 1,
showinfo: 1,
iv_load_policy: 3,
rel: 0
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
window.onPlayerReady = function(event) {
//wierd 404 errors sometimes
event.target.loadPlaylist(videoIds, 0, 0, 'large');
event.target.playVideo();
}
window.onPlayerStateChange = function(event) {
console.log('the state changed: '+ event.data);
if (event.data === 1) {
console.log(event.target.getDuration());
globalYoutubePlayerCounter++;
console.log('youtube player count: ' +globalYoutubePlayerCounter);
}
if (globalYoutubePlayerCounter >= 6) {
/* load the next set of videos */
globalYoutubePlayerCounter = 0;
console.log('playlist ended');
if (that.finalTrackList.length > 0) {
that.getNextTenMusic(event.target);
}else{
// recall for general searches;
// that.getNextTenGeneral(event.target);
}
/* load the next set of videos */
}
}
All video list is formatted correctly even when I get the error.
Console.log confirms this.
I had the same issue but with loadVideoById. For me, the problem was that the player hadn't fully initialized and therefore there really was no method loadVideoById. Maybe if someone faces the same problem, try postponing the call and see if that helps.
I was trying the following code from the samples given on developers.google.com/*
<script>
// 2. This code loads the IFrame Player API code asynchronously.
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: '390',
width: '640',
videoId: 'yZxrao3zou4',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
The code works perfectly when I have nothing else on my web page, but when I try to merge it with my project it doesn't seem to work.
I am guessing the problem is with the following lines:
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
Can someone tell me what does the above two lines do, especially the [0] part?
My code is pretty much the same except that instead of the script tag I have the code inside a function, which takes in a argument for the videoId.
EDIT:
My code is as follows:
<script>
// I have a input area, where the user can enter the movie name. When the user submits the movie name, I capture the val and pass it to the youtube().
function youtube(movie_name) {
var videoId;
$.ajax({
url:"https://www.googleapis.com/youtube/v3/search?part=snippet&q="+movie_name+"&type=video&key=my_key",
success: function (response) {
videoId = response.items[0].id.videoId;
findMovieById(videoId);
}
});
}
function findMovieById(videoID) {
$("#player").css('display', 'inline-block');
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: '390',
width: '640',
videoId: ""+videoID,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
alert('Player Ready');
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
}
</script>
The idea behind the sample code is that it is much more consistent when you load the YouTube iFrame library code after the rest of the page has loaded; hence the sample code demonstrates that you put an inline at the bottom of the page, and within that, you traverse the DOM, find a place where you can insert another tag, and do so dynamically (the [0] just says 'the first entry in the array of all elements of name in the document).
The logic here is that, when the iFrame library loads, it will call the function onYouTubeIframeAPIReady. But since the library loads asynchronously, it's best to load it this way to ensure that anything else that your API hooks might depend on (the element in the DOM you're binding to, for example) already exists.
Also note that, because the loaded library will always call the onYouTubeIframeAPIReady function, it MUST be defined outside any other function. Otherwise it isn't callable. That could be why nesting it inside your code somewhere isn't working.
Feel free to post some of your merged code for more detailed help.