Preventing YouTube From Autoplaying Behind Container

On Code 1 that uses 1 ClickHandler, YouTube starts playing right away before it is clicked.

On Code 2 that uses 2 ClickHandlers, YouTube doesn’t start playing before it is clicked.

How do I fix the code where YouTube starts playing right away, before it is clicked?

Should Code 1 that uses only 1 ClickHandler, should it be using 2 instead?

Would that fix the issue here?

(Code 1) uses 1 ClickHandler

YouTube Autoplays before it is clicked

Click “Run
or, YouTube starts after opening the link.
code: https://jsitor.com/88Ub5j2ZjO

(function iife() {
  "use strict";

  function show(el) {
    el.classList.remove("hide");
    document.querySelector(".container1").classList.add('slide');
  }

  function hide(el) {
    el.classList.add("hide");
   
  }

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    const thewrap = cover.parentNode.querySelector(".container");
    hide(cover);
    show(thewrap);
  }
  const cover = document.querySelector(".jacket");
  cover.addEventListener("click", coverClickHandler);
}());

const videoPlayer = (function makeVideoPlayer() {
  "use strict";

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

  function onPlayerStateChange(event) {
    const player = event.target;
    const shufflePlaylist = true;

    if (!hasShuffled) {
      player.setShuffle(shufflePlaylist);
      player.playVideoAt(0);
      hasShuffled = true;
    }
  }

  function addVideo(video) {

    const playlist = "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g";

    new YT.Player(video, {
      
      width: 640,
      height: 360,
      host: "https://www.youtube-nocookie.com",
      playerVars: {
        autoplay: 1,
        controls: 1,
        loop:1,
        rel: 0,
        iv_load_policy: 3,
        cc_load_policy: 0,
        fs: 0,
        disablekb: 1,
        playlist
      },
      events: {
        "onReady": onPlayerReady,
        "onStateChange": onPlayerStateChange
      }
    });
  }

  function init(opts) {
    load.js("https://www.youtube.com/player_api").then(function() {
      YT.ready(function() {
        addVideo(opts.video);
      });
    });
  }
  return {
    init
  };
}());

videoPlayer.init({
  video: document.querySelector(".video")
});

(Code 2) uses 2 ClickHandlers.

YouTube Does Not Autoplay before it is clicked

Which is how it should work.
code: https://jsitor.com/8OeEw1Xoj

(function manageCover() {
  "use strict";

  function hide(el) {
    el.classList.add("hide");
  }

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    hide(cover);
  }
  const cover = document.querySelector(".jacket");
  cover.addEventListener("click", coverClickHandler);
}());
const videoPlayer = (function makeVideoPlayer() {
  "use strict";

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

  function onPlayerStateChange(event) {
    const player = event.target;
    const shufflePlaylist = true;

    if (!hasShuffled) {
      player.setShuffle(shufflePlaylist);
      player.playVideoAt(0);
      hasShuffled = true;
    }
  }

  function addVideo(video) {

    const playlist = "0dgNc5S8cLI,mnfmQe8Mv1g,-Xgi_way56U,CHahce95B1g";

    new YT.Player(video, {

      width: 640,
      height: 360,
      host: "https://www.youtube-nocookie.com",
      playerVars: {
        autoplay: 1,
        controls: 1,
        loop: 1,
        rel: 0,
        iv_load_policy: 3,
        cc_load_policy: 0,
        fs: 0,
        disablekb: 1,
        playlist
      },
      events: {
        "onReady": onPlayerReady,
        "onStateChange": onPlayerStateChange
      }
    });
  }

  function init(opts) {
    load.js("https://www.youtube.com/player_api").then(function() {
      YT.ready(function() {
        addVideo(opts.video);
      });
    });
  }
  return {
    init
  };
}());

(function iife() {
  "use strict";

  function show(el) {
    el.classList.remove("hide");
  }

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

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

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

HTML inline events and JS event methods only allow one event method per element, which is why addEventListener was developed, for that allows you to have multiple event handlers on the same event of an element.

The question for you is does the code do what it’s supposed to do. It’s better to have the code separated so that related things are grouped together.

Does removing one of the e ent hand,ears or the other result in unwanted behavior?

Code 1 uses 1 ClickHandler

YouTube Autoplays before it is clicked: (Click Run)
code: https://jsitor.com/88Ub5j2ZjO

Code 1 should work the same as Code 2, where YouTube doesn’t start until it is clicked.

Code 2 uses 2 ClickHandlers

YouTube Does Not Autoplay before it is clicked (Click Run)
code: https://jsitor.com/8OeEw1Xoj

I don’t hear any sound from the play button. It’s only after the curtains pull aside and the video starts playing that sound is heard. Is that the sound from the video the sound that you mean?

Oh hang on, when waiting with the play button the video starts playing in the background. That is the unwanted behavoiur. You don’t want the video to start playing until you click the play button. I’m with you now.

1 Like

See

When you click run, sound can be heard before anything is clicked on the screen.

I want to prevent that.

Which is what the code that uses 2 clickhandlers does.

Now you’ve confused me because that doesn’t seem possible. Can you please break that down into more detail?

You had it right:

when waiting with the play button the video starts playing in the background. That is the unwanted behavior.

I need to prevent that.

Which code 2 does.

When opening link right away, youtube video starts playing before anything is clicked.

That or clicking where it says “Run” on the website.

code: https://jsitor.com/88Ub5j2ZjO

I’ll see what I can find out about it tomorrow.

1 Like

This should be able to help better test it.

Code 1
code: https://jsitor.com/xoVFN0or8

YouTube starts before anything is clicked.

Behind that there should be a black screen I believe, showing that it has not loaded.
In this state, YouTube should not be appearing on the screen at all.
It should only appear on the screen after it is clicked.

Code 2
code: https://jsitor.com/8OeEw1Xoj

Uses This, which causes the YouTube to never show/appear on the screen until it is clicked.

It also uses 2 ClinkHandlers which probably better separates everything out.

<div class="wrap hide">
<div class="video video-frame"></div>
</div>

I updated the class names here so it is easier to make out what each is.

Code 1

code https://jsitor.com/xoVFN0or8

curtain
container
panel
jacket

To reproduce issue, either Run buttons to run the code would need to be pressed.

I think it’s more like, “Preventing YouTube from being launched until one of the class names is clicked.”

That’s how Code 2 works I believe.
code: https://jsitor.com/8OeEw1Xoj

Maybe adding something like this to it?

(function manageCurtain() {
   "use strict";

   function hide(el) {
      el.classList.add("hide");
        document.querySelector(".curtain").classList.add("slide");
   }

   function coverClickHandler(evt) {
      const cover = evt.currentTarget;
      hide(cover);
   }
   const cover = document.querySelector(".jacket");
   cover.addEventListener("click", coverClickHandler);
}());

On investigating the last link that works, it’s because the video isn’t added until after someone clicks on the play button. That gives us a clue about how to get the troubled one to work. Don’t add the video until after the play button is clicked.

How we can achieve that is by updating the curtains so that it can receive information about what we want to do. That way we can tell the init section of the code to do the video thing when the curtains are opened.

First we update the curtains so that they accept config information:

// (function iife() {
const makeCurtains = function iife(config) {
  ...
// }());
};
makeCurtains({});

The coverClickHandler is where we check for a whenOpened function and run it.

  function coverClickHandler(evt) {
    ...
    hide(cover);
    show(thewrap);
    if (config.whenOpened instanceof Function) {
      config.whenOpened();
    }
  }

Then in the init area, we move the makeCurtains call to replace the video part.

  function init(opts) {
    const curtainsConfig = {};
    load.js("https://www.youtube.com/player_api").then(function () {
      YT.ready(function () {
        // addVideo(opts.video);
        makeCurtains(curtainsConfig);
      });
    });
  }

And lastly, we put the addVideo part into a curtains config method called whenPlayed.

  function init(opts) {
    const curtainsConfig = {
      whenOpened: function () {
        addVideo(opts.video);
      }
    };
    ...
  }

The code at https://jsitor.com/xoVFN0or8 has been updated, and seems to work.
Although, only one half of the curtains seems to be visible. That is a different issue to resolve.

2 Likes

I did that so it would easier to test the code, so you would be able to see what was happening behind it.

Fixed: https://jsitor.com/5Q0JNSawQH

Before I had the left side set to transparent.

.panel-left {
  left: 0%;
  /* background: transparent; */
  background-color: rgb(91, 96, 106);
}

Will there be a 2nd ClickHandler added to it?

This?


(function iife() {
  "use strict";

  function show(el) {
    el.classList.remove("hide");
  }

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

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

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

So it would look like this:

Would doing that help to organize, or separate the code out better?

    load.js("https://www.youtube.com/player_api").then(function () {
      YT.ready(function () {
        makeCurtains(curtainsConfig);
      });
    });
  }
  return {
    init
  };
}());

(function iife() {
  "use strict";

  function show(el) {
    el.classList.remove("hide");
  }

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

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

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

No there doesn’t have to be. It’s situational. Sometimes it’s better if there is, and sometimes if there isn’t.

How do you remove the testing (debug code) that you added to the code?

code https://jsfiddle.net/jbhLgpod/1/

code https://jsitor.com/xoVFN0or8

This stuff?

    if (config.whenOpened instanceof Function) {
      config.whenOpened();
    }

I think in here also?

  function init(opts) {
    const curtainsConfig = {
      whenOpened: function () {
        addVideo(opts.video);
      }

And in here:

      YT.ready(function () {
        makeCurtains(curtainsConfig);
      });
    });

I tried to do it myself but the code kept breaking after removing it.

How do I remove the testing code from the javascript without breaking it?

Every time I attempt it doesn’t work.

code https://jsitor.com/xoVFN0or8

const makeCurtains = function iife(config) {
  "use strict";

  function show(el) {
    el.classList.remove("hide");
    document.querySelector(".curtain").classList.add("slide");
  }

  function hide(el) {
    el.classList.add("hide");
  }

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    const thewrap = cover.parentNode.querySelector(".container");
    hide(cover);
    show(thewrap);
    if (config.whenOpened instanceof Function) {
      config.whenOpened();
    }
  }
  const cover = document.querySelector(".jacket");
  cover.addEventListener("click", coverClickHandler);
};


const videoPlayer = (function makeVideoPlayer() {
  "use strict";

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

  function onPlayerStateChange(event) {
    const player = event.target;
    const shufflePlaylist = true;

    if (!hasShuffled) {
      player.setShuffle(shufflePlaylist);
      player.playVideoAt(0);
      hasShuffled = true;
    }
  }

  function addVideo(video) {

    const playlist = "M7lc1UVf-VE";

    new YT.Player(video, {

      width: 640,
      height: 360,
      host: "https://www.youtube-nocookie.com",
      playerVars: {
        autoplay: 1,
        controls: 1,
        loop: 1,
        rel: 0,
        iv_load_policy: 3,
        cc_load_policy: 0,
        fs: 0,
        disablekb: 1,
        playlist
      },
      events: {
        "onReady": onPlayerReady,
        "onStateChange": onPlayerStateChange
      }
    });
  }

  function init(opts) {
    const curtainsConfig = {
      whenOpened: function () {
        addVideo(opts.video);
      }
    };
    load.js("https://www.youtube.com/player_api").then(function () {
      YT.ready(function () {
        makeCurtains(curtainsConfig);
      });
    });
  }
  return {
    init
  };
}());

videoPlayer.init({
  video: document.querySelector(".video")
});

That is not testing code.

That code should be in the main code to ensure that the whenOpened property is a function before it gets executed.

1 Like

Stop removing it. It really should be there.

1 Like

I did not know that, thank you for telling me.

What about this way of doing it?

videoPlayer.init inside coverClickHandler

So that way, video is only loaded when you click on the cover.

Is this way good or no?

code: https://jsfiddle.net/86na4tzv/1/

  function coverClickHandler(evt) {
      const cover = evt.currentTarget;
      const thewrap = cover.parentNode.querySelector(".container");
      hide(cover);
      videoPlayer.init({
         video: document.querySelector(".video")
      });
      show(thewrap);
   }