What is the purpose of the load function?

Doing things more properly according to Google means making several changes.

The good news is that the following code needs to run immediately when the page loads:

  const tag = document.createElement('script');
  tag.src = "https://www.youtube.com/iframe_api";
  const firstScriptTag = document.getElementsByTagName('script')[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

That is correctly being done at the start of the videoPlayer IIFE (immediately invoked function expression).

The onYouTubeIframeAPIReady function though is not for us to run in the code. That needs to be globally accessible (outside of any other functions) so that the API can automatically run that function when the API is ready.

I’m going to rename what you have there to addPlayer and make that available from the videoPlayer code. I am also setting autoplay to 0, so that it doesn’t start playing as soon as the iframe is created. I’ll add code to play the video afterwards.

  // function onYouTubeIframeAPIReady(video) {
  function addPlayer(video) {
    const playlist = "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g";
    new YT.Player(video, {
...
      playerVars: {
        // autoplay: 1,
        autoplay: 0,
...
  // function init(opts) {
  //   onYouTubeIframeAPIReady(opts.video);
  // }
  return {
    addPlayer
  };
}());

and below that, we’ll have a globally accessible function called onYouTubeIframeAPIReady

function onYouTubeIframeAPIReady() {
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
}

The wrapper is not yet available. We can’t pass config information to the onYouTubeIframeAPIReady function, so we’ll get that config information from else where.

Where is a good place for config information? At the top of the code of course.

const cover = document.querySelector(".jacket");
...
  // const cover = document.querySelector(".jacket");
  cover.addEventListener("click", coverClickHandler);

We can now refer to that cover from within the onYouTubeIframeAPIReady function too:

function onYouTubeIframeAPIReady() {
    const wrapper = cover.nextElementSibling;
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
}

When the player is ready, the onPlayerReady function is run:

  function onPlayerReady(event) {
    const player = event.target;
    player.setVolume(100); // percent
  }

We want to later on play the video when someone clicks on the cover. It is from that onPlayerReady function that we save aside a reference to the player.

const videoPlayer = (function makeVideoPlayer() {
  "use strict";
  let player = null;
...
  function onPlayerReady(event) {
    // const player = event.target;
    player = event.target;
    player.setVolume(100); // percent
  }

That way, when the cover is clicked, we can have the videoPlayer code play the video.

  function play() {
    player.playVideo();
  }
  return {
    addPlayer,
    play
  };
}());

Lastly, we remove the initPlayer code because the different videoPlayer.play code is being used instead.

  // function initPlayer(wrapper) {
  //   videoPlayer.init({
  //     video: wrapper.querySelector(".video")
  //   });
  // }

  function coverClickHandler(evt) {
    const wrapper = evt.currentTarget.nextElementSibling;
    show(wrapper);
    // initPlayer(wrapper);
    videoPlayer.play();
  }

The way it all works is that the iframe_api is loaded as soon as possible, which when loaded creates the iframe as soon as possible. The video is ready and waiting, but not playing.
Later on when we click the cover, the video starts playing.

The updated code is at https://jsfiddle.net/71y52qa8/

1 Like