Keeping YouTube hidden behind cover until it is clicked

How it should work is:

After it is clicked, YouTube should appear on the screen, but it is not.

What needs to be fixed/adjusted in the code for that to occur?

I get an error message after I click on it, but I am not sure if that is the cause of YouTube not appearing on the screen.

code https://jsfiddle.net/rsbwe91z/

html,
body {
  height: 100%;
  background: #000000;
  padding: 0;
  margin: 0;
}

.outer {
  display: table;
  height: 100%;
  margin: 0 auto;
  width: 100%;
}

.tcell {
  display: table-cell;
  vertical-align: middle;
  padding: 8px 8px;
}

.curtain-wrapper {
  min-width: 40%;
  max-width: 640px;
  margin: auto;
}

.curtain-ratio-keeper {
  position: relative;
  padding-top: 56.25%;
}

.curtain {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  width: 100%;
  height: 100%;
  border: 3px solid red;
  box-sizing: border-box;
  border-radius: 25px;
  overflow: hidden;
  background: transparent;
}

.container {}

.panel-left,
.panel-right {
  position: absolute;
  height: 100%;
  width: 50%;
  top: 0%;
  transition: all ease 8s;
}

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

.panel-right {
  left: 50%;
  background-color: rgb(229, 211, 211);
}

.curtain.slide .panel-left {
  transform: translateX(-100%);
}

.curtain.slide .panel-right {
  transform: translateX(100%);
}

.video-wrapper {
  min-width: 40%;
  max-width: 640px;
  margin: auto;
}

.video-ratio-keeper {
  position: relative;
  padding-top: 56.25%;
}

.video-frame {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.jacket {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  height: 100%;
  width: 100%;
  margin: auto;
  cursor: pointer;
  border-radius: 25px;
}

.play {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  margin: auto;
  min-width: 70px;
  min-height: 70px;
  max-width: 30%;
  max-height: 30%;
  fill: red;
  filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.7));
  cursor: pointer;
}

.wrap {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 25px;
}

.wrap,
.jacket {
  position: absolute;
  top: -3px;
  left: -3px;
  width: calc(100% + 6px);
  height: calc(100% + 6px);
}

.wrap iframe {
  position: absolute;
  top: -3px;
  left: -3px;
  width: calc(100% + 6px);
  height: calc(100% + 6px);
}

.hide {
  display: none;
}

<div class="outer">
   <div class="tcell">
      <div class="curtain-wrapper">
         <div class="curtain-ratio-keeper">
            <div class="curtain">
               <div class="container hide">
                  <div class="video-wrapper">
                     <div class="video-ratio-keeper">
                     </div>
                  </div>
               </div>
               <div class="panel-left"></div>
               <div class="wrap hide">
                  <div class="video video-frame"></div>
               </div>
               <div class="panel-right"></div>
            </div>
            <div class="jacket" title="Play">
               <svg class="play" width="100%" height="100%" viewBox="0 0 64 64">
                  <path d="M25.6,46.4L44.8,32L25.6,17.6V46.4z M32,0C14.3,0,0,14.3,0,32s14.3,32,32,32s32-14.3,32-32S49.7,0,32,0z
                     M32,57.6C17.9,57.6,6.4,46.1,6.4,32S17.9,6.4,32,6.4S57.6,17.9,57.6,32S46.1,57.6,32,57.6z" />
               </svg>
            </div>
         </div>
      </div>
   </div>
</div>
const load = (function () {
   "use strict";

   function _load(tag) {
      return function (url) {
         return new Promise(function (resolve) {
            const element = document.createElement(tag);
            const parent = "body";
            const attr = "src";
            element.onload = function () {
               resolve(url);
            };
            element[attr] = url;
            document[parent].appendChild(element);
         });
      };
   }
   return {
      js: _load("script")
   };
}());

(function manageCover() {
   "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);

   }
   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: 0,
            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);
}());

I would definitely fix that error first. The error is in the show function, which is called before the initPlayer function, so initPlayer is never being executed.

1 Like

How would I go about fixing it?

You mean in here:



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);
   }

Something else should go here I believe.

evt.currentTarget.nextElementSibling

So this is part of learning to program, learning how to troubleshoot and debug. Are you familiar with your browser’s dev tools? If not you’ll want to be, it is your best friend. Open it up, go to the Console tab, click on your app and see the error message appear. In Firefox it gives you the error itself and then a stack trace so you can see in which function the error occurred. The trace ends at the show function. I can also click on the show function in the console and it will open the code in the Debugger and point me to the exact line where the error is occurring.

The error is

Uncaught TypeError: el is null

This means that in the show function the variable el that you are passing in is null and thus you can’t call any methods on it, like classList.remove(). Your job is to figure out why el is null instead of pointing to the appropriate element in the DOM.

1 Like

How do I fix this error?

code https://jsfiddle.net/fjrvd46z/7/

I believe it is in this part of the code.

(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);
}());

Try logging out the el parameter inside the show function.

1 Like

What do you mean?

I don’t understand.

What do you mean by logging out?

console.log() the values.

Log out the el value so you can see what it is, it’s null. Now look at where the value is coming from and again log it out, wrapper is null. Now log out evt inside coverClickHandler and look at the list of properties and their values.

1 Like

You also have two IIFEs that are doing some of the same things. So you end up with two click handlers on the same element.

You can use this inside coverClickHandler to get to the element. Not sure what element it is you are trying to get to using nextElementSibling though.

1 Like

It seems like the two threads are related so I merged them.

1 Like

I got it I think.

code https://jsfiddle.net/uonwq2zc/3/

const load = (function () {
   "use strict";

   function _load(tag) {
      return function (url) {
         return new Promise(function (resolve) {
            const element = document.createElement(tag);
            const parent = "body";
            const attr = "src";
            element.onload = function () {
               resolve(url);
            };
            element[attr] = url;
            document[parent].appendChild(element);
         });
      };
   }
   return {
      js: _load("script")
   };
}());

(function iife() {
   "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);
   }
   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 = "CHahce95B1g";

      new YT.Player(video, {

         width: 640,
         height: 360,
         host: "https://www.youtube-nocookie.com",
         playerVars: {
            autoplay: 0,
            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")
});

Right now YouTube is currently visible as you can see in the image, and jsfiddle code I provided.

How do I keep YouTube from loading on the screen until the image/cover is clicked?

After the cover is clicked, then I want the YouTube to appear on the screen.

How do I do this?

code https://jsfiddle.net/z8owdL2e/

html,
body {
  height: 100%;
  background: #000000;
  padding: 0;
  margin: 0;
}

.outer {
  display: table;
  height: 100%;
  margin: 0 auto;
  width: 100%;
}

.tcell {
  display: table-cell;
  vertical-align: middle;
  padding: 8px 8px;
}

.curtain-wrapper {
  min-width: 40%;
  max-width: 640px;
  margin: auto;
}

.curtain-ratio-keeper {
  position: relative;
  padding-top: 56.25%;
  /* overflow: hidden; */
}

.curtain {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  width: 100%;
  height: 100%;
  border: 3px solid red;
  box-sizing: border-box;
  border-radius: 25px;
  overflow: hidden;
  background: teal;
}

.container {}

.panel-left,
.panel-right {
  position: absolute;
  height: 100%;
  width: 50%;
  top: 0%;
  transition: all ease 8s;
  /* border: 3px solid red;8 */
}

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

.panel-right {
  left: 50%;
  background-color: rgb(229, 211, 211);
}

.curtain.slide .panel-left {
  /*left: -50%;*/
  transform: translateX(-100%);
}

.curtain.slide .panel-right {
  /* left: 100%;*/
  transform: translateX(100%);
}

.video-wrapper {
  min-width: 40%;
  max-width: 640px;
  margin: auto;
}

.video-ratio-keeper {
  position: relative;
  padding-top: 56.25%;
}

.video-frame {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.jacket {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  height: 100%;
  width: 100%;
  margin: auto;
  cursor: pointer;
  border-radius: 25px;
}

.play {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  margin: auto;
  min-width: 70px;
  min-height: 70px;
  max-width: 30%;
  max-height: 30%;
  fill: red;
  filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.7));
  cursor: pointer;
}

.wrap {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 25px;
}

.wrap,
.jacket {
  position: absolute;
  top: -3px;
  left: -3px;
  width: calc(100% + 6px);
  height: calc(100% + 6px);
}

.wrap iframe {
  position: absolute;
  top: -3px;
  left: -3px;
  width: calc(100% + 6px);
  height: calc(100% + 6px);
}

.hide {
  display: none;
}

<div class="outer">
   <div class="tcell">
      <div class="curtain-wrapper">
         <div class="curtain-ratio-keeper">
            <div class="curtain">
               <div class="container hide">
                  <div class="video-wrapper">
                     <div class="video-ratio-keeper">
                     </div>
                  </div>
               </div>
               <div class="panel-left"></div>
               <div class="wrap ">
                  <div class="video video-frame"></div>
               </div>
               <div class="panel-right"></div>
            </div>
            <div class="jacket" title="Play">
               <svg class="play" width="100%" height="100%" viewBox="0 0 64 64">
                  <path d="M25.6,46.4L44.8,32L25.6,17.6V46.4z M32,0C14.3,0,0,14.3,0,32s14.3,32,32,32s32-14.3,32-32S49.7,0,32,0z
                     M32,57.6C17.9,57.6,6.4,46.1,6.4,32S17.9,6.4,32,6.4S57.6,17.9,57.6,32S46.1,57.6,32,57.6z" />
               </svg>
            </div>
         </div>
      </div>
   </div>
</div>
const load = (function () {
   "use strict";

   function _load(tag) {
      return function (url) {
         return new Promise(function (resolve) {
            const element = document.createElement(tag);
            const parent = "body";
            const attr = "src";
            element.onload = function () {
               resolve(url);
            };
            element[attr] = url;
            document[parent].appendChild(element);
         });
      };
   }
   return {
      js: _load("script")
   };
}());

(function iife() {
   "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);
   }
   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 = "CHahce95B1g";

      new YT.Player(video, {

         width: 640,
         height: 360,
         host: "https://www.youtube-nocookie.com",
         playerVars: {
            autoplay: 0,
            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")
});

After all the work you’ve done on this up to this point I would be very surprised if you couldn’t think of a way to do this on your own. You’ve asked for a lot of help on this particular project so far, which is fine, that’s what this forum is for, but I sort of feel like you are relying maybe a little too much on our help instead of trying to solve it yourself first.

I think the better approach would be for you to make a legitimate attempt at solving this and if you get stuck on something you can show us your code and ask us for guidance. But just telling us what you want to do and then asking us how to do it is basically asking us to code your project for you.

This is just my personal opinion. I don’t mean to come off as a jerk and if I do I apologize. But I’d rather see you make an honest attempt, which may take a day or two, and then come back with specific questions about your code if it isn’t working.

1 Like

Is this a good way?

I’m still working on it, not done yet.

code https://jsfiddle.net/0u8khzdc/

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: 0,
            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")
});

If it does what you want it to do and it works in all the major browsers then I would say it is good. There is usually more than one way to do something and sometimes one way is not better than any other.

Congrats on getting this working.

I came back to this because I wanted to try and figure it out.

I would change:

evt.currentTarget.nextElementSibling

to

evt.currentTarget.parentElement;

Am I right?

Is that what needed to be there?

code: https://jsfiddle.net/b7ksh9mq/

(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.parentElement;
    show(wrapper);
    initPlayer(wrapper);
  }

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

I don’t know because I don’t know what you are trying to accomplish with this change. You need to describe exactly what you are trying to do and explain why you did it.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.