I hope someone can help with this. I am getting the following error Uncaught TypeError: YT.Player is not a constructor when I am on one tab of about 5 on my page. I click on a button on the page, and it brings up a modal window from which I make a selection and upon the closing of the modal window in the console that error is shown.
What is frustrating is that using the same data with the same compile arguments as production, I cannot get this error to replicate itself in our Dev or Staging environments. The one difference is that our production servers sit behind a NetScaler. Could the NetScaler be the issue?
Below is my Video code.
<div class="videocontainer">
@if (!string.IsNullOrEmpty(video.VideoURL))
{
<script type="text/javascript">
var _gVideoTracked = false;
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
events: { 'onStateChange': onPlayerStateChange }
});
}
function onPlayerStateChange(event) {
switch (event.data) {
case 0:
break;
case 1:
if (!_gVideoTracked) {
BaGaTrack('Video Played', 'Played')
}
_gVideoTracked = true;
break;
case 2:
}
}
$(document).ready(function () {
$.getScript("https://www.youtube.com/iframe_api", function () {
player = new YT.Player('player', {
events: { 'onStateChange': onPlayerStateChange }
});
});
});
</script>
<iframe id="player" src="@video.VideoURL/?enablejsapi=1" allowfullscreen class="video"></iframe>
}
</div>
There seems to be an undocumented API, YT.ready
.
Not found in their documentation: https://developers.google.com/youtube/iframe_api_reference
In my case, I had to wrap new YT.Player
within YT.read()
as shown below.
function setupPlayer() {
/**
* THIS FAILS!!!!!
*/
// player = new YT.Player("player", {
// height: "390",
// width: "640",
// videoId: "M7lc1UVf-VE",
// events: {
// onReady: onPlayerReady,
// onStateChange: onPlayerStateChange
// }
// });
/**
* Need to wait until Youtube Player is ready!
*/
window.YT.ready(function() {
player = new window.YT.Player("video", {
height: "390",
width: "640",
videoId: "M7lc1UVf-VE",
events: {
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
});
}
I found it via this CodeSanbox sample, https://codesandbox.io/s/youtube-iframe-api-tpjwj
It uses jQuery and I reimplemented it using Vanilla JS below.
https://codesandbox.io/s/soanswer52062169-mem83
For completeness, here is the JavaScript code.
function loadVideo() {
console.info(`loadVideo called`);
(function loadYoutubeIFrameApiScript() {
const tag = document.createElement("script");
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
tag.onload = setupPlayer;
})();
let player = null;
function setupPlayer() {
/**
* THIS FAILS!!!!!
*/
// player = new YT.Player("player", {
// height: "390",
// width: "640",
// videoId: "M7lc1UVf-VE",
// events: {
// onReady: onPlayerReady,
// onStateChange: onPlayerStateChange
// }
// });
/**
* Need to wait until Youtube Player is ready!
*
* YT.ready is not documented in https://developers.google.com/youtube/iframe_api_reference
* but found from https://codesandbox.io/s/youtube-iframe-api-tpjwj
*/
window.YT.ready(function() {
player = new window.YT.Player("video", {
height: "390",
width: "640",
videoId: "M7lc1UVf-VE",
events: {
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
});
}
function onPlayerReady(event) {
event.target.playVideo();
}
function onPlayerStateChange(event) {
var videoStatuses = Object.entries(window.YT.PlayerState);
console.log(videoStatuses.find(status => status[1] === event.data)[0]);
}
}
if (document.readyState !== "loading") {
console.info(`document.readyState ==>`, document.readyState);
loadVideo();
} else {
document.addEventListener("DOMContentLoaded", function() {
console.info(`DOMContentLoaded ==>`, document.readyState);
loadVideo();
});
}
Turns out including the API synchronously doesn't matter (using URL https://www.youtube.com/iframe_api
) since the code returned loads the API asynchronously anyway. The instructions are misleading (figures), giving the impression that loading using a direct script link would be synchronous, but that is not the case. As such new YT.Player
fails simply because the player 'type' is undefined
.
And this is the event you need to wait for:
Any web page that uses the IFrame API must also implement the following JavaScript function:
onYouTubeIframeAPIReady – The API will call this function when the page has finished downloading the JavaScript for the player API, which enables you to then use the API on your page. Thus, this function might create the player objects that you want to display when the page loads.
Warning: Some player-specific functions are also missing until a player itself finishes loading (triggers the "ready" event).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With