Clicking one element to remove a different element

What I want to do is remove the lines by clicking the video class.
Setting it up this way will help me better understand how this is done.

<div class="wrapg">
  <div class="video"></div>
  <div class="lines"></div>
</div>

This is clicking the lines and they disappear.

This is clicking the video class and the lines appear.

I want to click the video class and the lines disappear.

I’m stuck.

How do you do this?

Working from the code in the second link you posted.

  1. The video div has no content, height, or styles at this point so it is an empty div. There is nothing holding it open to be able to get a click event to happen.
  2. So put some dummy content or styles on it so it has a target area.
  3. Remove the .hide class from .lines

<div class="wrapg ">
  <div class="video">I am the video div, click here</div>
  <div class="lines"></div>
</div>
.video {  
  background:red; 
}

Now you have something to click…

To click on the video div then make that adjustment to your JS starting on line 25 of the fiddle.

Target the .video class then let the click event add the .hide class to .lines with .classList.add

(function iife() {
  "use strict";
  document.querySelector(".video").addEventListener("click", function() {
    document.querySelector(".lines").classList.add("hide");
  });
}());

Will that work after adding a video in?

The lines should be removed after the iframe is clicked.

It’s an iframe, not a div, so it works differently I think.

I was explaining why your fiddle didn’t work and what you needed to do to get it working.

If you place your iframe in the video div then it WILL have content to hold it open and then there will be no need for the dummy text I placed in it.

It should still work with the iframe only since you have the video class on it, as seen in the html of the 138 fiddle you just posted

<iframe class="js-player video"

1 Like

The lines aren’t disappearing after it’s clicked:
What am I doing wrong?

<div class="wrapg ">
    <iframe class="js-player video" src="https://www.youtube-nocookie.com/embed/M7lc1UVf-VE?rel=0&autoplay=0&controls=0&iv_load_policy=3&cc_load_policy=0&fs=0&disablekb=1&enablejsapi=1" frameborder="0" allow="autoplay; encrypted-media"></iframe>
  <div class="lines"></div>
</div>

I see that, then try nesting the iframe in the video div. You can remove the .video class from the iframe in that case.

<div class="wrapg ">
  <div class="video">
   <iframe class="js-player" src="https://www.youtube-nocookie.com/embed/M7lc1UVf-VE?rel=0&autoplay=0&controls=0&iv_load_policy=3&cc_load_policy=0&fs=0&disablekb=1&enablejsapi=1" frameborder="0" allow="autoplay; encrypted-media"></iframe>
  </div>
  <div class="lines"></div>
</div>

The lines are still not disappearing:

These are meant to go together:


 <div class="lines hide"></div>

document.querySelector(".lines").classList.add("hide");

I should not be using this code, I don’t think:

(function iife() {
  "use strict";
  document.querySelector(".video").addEventListener("click", function() {
    document.querySelector(".lines").classList.add("hide");
  });
}());

Only the upper part:


(function iife() {
  "use strict";

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

  function hideInitialOverlay(wrapper) {
    hide(wrapper);
  }

  function initialOverlayClickHandler() {
    var wrapper = document.querySelector(".lines");
    hideInitialOverlay(wrapper);
    wrapper.removeEventListener("click", initialOverlayClickHandler);
  }

  function initButton(selector) {
    var wrapper = document.querySelector(selector);
    wrapper.addEventListener("click", initialOverlayClickHandler);
  }
  initButton(".lines");
}());

Which I was thinking using something like this:


    function hideInitialOverlay(wrapper) {
        wrapper.classList.remove("inactive");
        wrapper.classList.add("active");
}


.wrapg/*.active*/ .lines::before,
.wrapg/*.active*/ .lines::after {
  content: "";
  position: absolute;
  top: 0;
  left: 198px;
  width: 3px;
  height: 100%;
  background: #0059dd;
}

.wrapg/*.active*/ .lines::after {
  left: 399px;
}

.wrapg.inactive .wrapg .lines {
  display: none;
}

By any chance, have you noticed that the youtube playbutton stays after a few seconds after clicking it?

I read your other thread about it, I had it stay in place a few times but it always disappeared later. I have no answers for that, it is being caused by the AP lines like Paul had mentioned.

The iframe seems to be changing the way things work with your JS in regards to this thread. I don’t think I will have much other advice to offer, it has me stumped.

The lines don’t seem to get along well with the iframe.

1 Like

I think it’s the pseudo elements ::before and ::after interfering with the youtube svg button.

<button class="ytp-large-play-button ytp-button" aria-label="Play"><svg height="100%" version="1.1" viewBox="0 0 68 48" width="100%"><path class="ytp-large-play-button-bg" d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z" fill="#212121" fill-opacity="0.8"></path><path d="M 45,24 27,14 27,34" fill="#fff"></path></svg></button>

So then I was trying to figure out how to remove the lines once the iframe is clicked. But I still haven’t been able to figure that out.

It looks like you’ve been making several changes to the code in https://jsfiddle.net/zb6mkug3/136/ without understanding the impact of those changes.

For example:

    var wrapper = document.querySelector(".lines");
    hideInitialOverlay(wrapper);

The wrapper is the wrapg element, not the one with lines, there is no initial overlay at the lines area, and you’re calling code that’s designed to hide the initial overlay based on the wrapper. without even giving it the wrapper.

That the code even vaguely does something that you want after what you’ve done to it, seems to be a completely coincidental.

There doesn’t seem to be any overlay with what you’ve done now. Instead with what you’re wanting to achieve, there are two different triggers for things to occur. One trigger is when you click on the lines, and the other is when you start playing the video.

With hiding those lines, much of the code can be removed, and replaced with a simple hide function:

    const lines = document.querySelector(".lines");
    function hideLines() {
        lines.classList.add("hide");
    }
    function clickHandler(evt) {
        hideLines();
    }
    lines.addEventListener("click", clickHandler);

The important thing about the above changes is that there is a separate hideLines() function that can be called from multiple places, because we also want the video player to hide those lines too.

We can also add an event handler for when the video changes state.

    function onPlayerStateChange(evt) {
        // possible states values are:
        // -1 (unstarted), 0 (ended), 1 (playing),
        // 2 (paused), 3 (buffering), 5 (video cued).
        var state = evt.data;
        if (state > 0) {
            hideLines();
        }
    }
...
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }

And lastly, we can add a player variable to the top of the code, so that we can access the player when the lines are clicked.

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

And the code now seems to behave in the way that is desired.

Clicking on the lines causes them to be hidden and plays the video, and playing the video causes the lines to be hidden.

3 Likes

I do want an overlay which I added in here:

And you would just add that code on top of the other one, right?

Or would I combine them into 1 code, and is that possible to do?

Overlay

(function iife() {
  "use strict";

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

  function hideInitialOverlay(wrapper) {
    hide(wrapper);
  }

  function initialOverlayClickHandler() {
    var wrapper = document.querySelector(".jacketc");
    hideInitialOverlay(wrapper);
    wrapper.removeEventListener("click", initialOverlayClickHandler);
  }

  function initButton(selector) {
    var wrapper = document.querySelector(selector);
    wrapper.addEventListener("click", initialOverlayClickHandler);
  }
  initButton(".jacketc");
}());

(function iife() {
  "use strict";
  document.querySelector(".jacketc").addEventListener("click", function() {
    document.querySelector(".wrapg").classList.remove("hide");
  });
}());

Goes on top of the line code:

(function iife() {
    "use strict";

    let player = {};
    const lines = document.querySelector(".wrapg .lines");

    function hideLines() {
        lines.classList.add("hide");
    }
    function clickHandler() {
        hideLines();
        player.playVideo();
    }
    lines.addEventListener("click", clickHandler);

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

    function onPlayerReady(event) {
        player = event.target;
        player.setVolume(100); // percent
    }
    function onPlayerStateChange(evt) {
        // possible states values are:
        // -1 (unstarted), 0 (ended), 1 (playing),
        // 2 (paused), 3 (buffering), 5 (video cued).
        const state = evt.data;
        if (state > 0) {
            hideLines();
        }
    }
    window.onYouTubePlayerAPIReady = function () {
        new YT.Player(document.querySelector(".js-player"), {
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        });
    };
}());

This is the Overlay code using const

Would I then be adding the line code into here somehow, or would I be keeping both codes separate from each other, how the above code is set up?

And maybe it’s better to keep both codes separate, than together.


(function iife() {
  "use strict";

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

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

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    const thevid = cover.parentNode.querySelector(".wrapg");
    const thewrap = cover.parentNode;
    hide(cover);
    show(thevid);

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

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

  function onPlayerReady(event) {
    const youtubePlayer = event.target;
    youtubePlayer.setVolume(100); // percent
  }
  window.onYouTubePlayerAPIReady = function() {
    new YT.Player(document.querySelector(".js-player"), {
      events: {
        "onReady": onPlayerReady
      }
    });
  };
}());

Keeping the vertical lines, resolving a bug / issue.

If I kept the lines, would you have known how to resolve this issue with the playbutton staying a few more seconds before it disappears? @PaulOb was able to reproduce the issue, but he wasn’t able to find a way to fix it. #6 #9

I think it’s the pseudo elements ::before and ::after interfering with the youtube svg button somehow which won’t allow for it to disappear right away.

<button class="ytp-large-play-button ytp-button" aria-label="Play"><svg height="100%" version="1.1" viewBox="0 0 68 48" width="100%"><path class="ytp-large-play-button-bg" d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z" fill="#212121" fill-opacity="0.8"></path><path d="M 45,24 27,14 27,34" fill="#fff"></path></svg></button>

Would there be a javascript fix for that?

With the code you just did, with removing the lines, the playbutton disappears right away, there’s no issue with that there.

Would you know what a possible solution would be to address the issue with the playbutton staying longer than it’s supposed to if the lines were to be kept?

Would there be some way to target the YouTube Playbutton itself so it removes right away as is shown below? Without targeting the lines, just the button?

Playbutton takes more time to disappear

  function hideLines() {
        lines.classList.add("");
    }

Playbutton disappears right away

  function hideLines() {
        lines.classList.add("hide");
    }

Just to clarify before @Paul_Wilkins or any other JS guru replies: :slight_smile:

Yes I managed to reproduce the issue 50% of the time in Firefox but you need to scroll the page up and down a bit first.

It’s not limited to the pseudo class but anything that is absolutely positioned over the iframe.

1 Like

What’s the difference between:

Jslint wanted “var” instead of “let” so I changed it to var.

Wait, jslint isn’t asking me to change that now.

Should it be “var,” or “let” then?

YouTube api shows this:
var player;

and

You put this:
let player = {};

Which should it be?
Both ways work.

Using var is the old way of doing things. Using const and let is the preferred way of doing things, because it gives you more control.

const is used for variables that aren’t going to change. It’s preferred to use const as much as possible, for then you know that the variable isn’t going to change.
let is used for variables that can change. Because it’s more difficult to keep track of what changes have occurred to variables, it’s best to prefer const instead of let.

In summary, use const as much as you can. Use let when you have to. Don’t use var.

2 Likes

I would like your thoughts and opinion on this.

I was able to put the code together like this, that includes the Overlay.

But, I don’t like putting all the code in there like that.


(function iife() {
  "use strict";

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

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

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    const thevid = cover.parentNode.querySelector(".wrapg");
    const thewrap = cover.parentNode;
    hide(cover);
    show(thevid);

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


  let player = {};
  const lines = document.querySelector(".wrapg .lines");

  function hideLines() {
    lines.classList.add("hide");
  }

  function clickHandler() {
    hideLines();
    player.playVideo();
  }
  lines.addEventListener("click", clickHandler);

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

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

  function onPlayerStateChange(evt) {
    // possible states values are:
    // -1 (unstarted), 0 (ended), 1 (playing),
    // 2 (paused), 3 (buffering), 5 (video cued).
    const state = evt.data;
    if (state > 0) {
      hideLines();
    }
  }
  window.onYouTubePlayerAPIReady = function() {
    new YT.Player(document.querySelector(".js-player"), {
      events: {
        "onReady": onPlayerReady,
        "onStateChange": onPlayerStateChange
      }
    });
  };
}());

I seem to like having the cover overlay separate from the YouTube code.
Because then it’s not all bunched up together, and so it’s easier to manage.

Do you agree?

Overlay Cover


(function iife() {
  "use strict";

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

  function hideInitialOverlay(wrapper) {
    hide(wrapper);
  }

  function initialOverlayClickHandler() {
    var wrapper = document.querySelector(".jacketc");
    hideInitialOverlay(wrapper);
    wrapper.removeEventListener("click", initialOverlayClickHandler);
  }

  function initButton(selector) {
    var wrapper = document.querySelector(selector);
    wrapper.addEventListener("click", initialOverlayClickHandler);
  }
  initButton(".jacketc");
}());

(function iife() {
  "use strict";
  document.querySelector(".jacketc").addEventListener("click", function() {
    document.querySelector(".wrapg").classList.remove("hide");
  });
}());

YouTube Code


(function iife() {
    "use strict";

    let player = {};
    const lines = document.querySelector(".wrapg .lines");

    function hideLines() {
        lines.classList.add("hide");
    }
    function clickHandler() {
        hideLines();
        player.playVideo();
    }
    lines.addEventListener("click", clickHandler);

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

    function onPlayerReady(event) {
        player = event.target;
        player.setVolume(100); // percent
    }
    function onPlayerStateChange(evt) {
        // possible states values are:
        // -1 (unstarted), 0 (ended), 1 (playing),
        // 2 (paused), 3 (buffering), 5 (video cued).
        const state = evt.data;
        if (state > 0) {
            hideLines();
        }
    }
    window.onYouTubePlayerAPIReady = function () {
        new YT.Player(document.querySelector(".js-player"), {
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        });
    };
}());

I agree, it’s better to have a good separation of concerns.

In this case it’s better to have the youtube code happen first, so that we can gain a reference to the youtube player, and then give that player reference to the code that does the overlay and lines.

I won’t have time today to help with that though, but perhaps tomorrow.

1 Like

Like this:

I should reverse it, is that what you’re saying?

YouTube Code
Overlay Cover

Shouldn’t the Overlay Cover come first though?

And then the YouTube Code under it?

YouTube Code


(function iife() {
    "use strict";

    let player = {};
    const lines = document.querySelector(".wrapg .lines");

    function hideLines() {
        lines.classList.add("hide");
    }
    function clickHandler() {
        hideLines();
        player.playVideo();
    }
    lines.addEventListener("click", clickHandler);

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

    function onPlayerReady(event) {
        player = event.target;
        player.setVolume(100); // percent
    }
    function onPlayerStateChange(evt) {
        // possible states values are:
        // -1 (unstarted), 0 (ended), 1 (playing),
        // 2 (paused), 3 (buffering), 5 (video cued).
        const state = evt.data;
        if (state > 0) {
            hideLines();
        }
    }
    window.onYouTubePlayerAPIReady = function () {
        new YT.Player(document.querySelector(".js-player"), {
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        });
    };
}());

Overlay Cover:

(function iife() {
  "use strict";

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

  function hideInitialOverlay(wrapper) {
    hide(wrapper);
  }

  function initialOverlayClickHandler() {
    var wrapper = document.querySelector(".jacketc");
    hideInitialOverlay(wrapper);
    wrapper.removeEventListener("click", initialOverlayClickHandler);
  }

  function initButton(selector) {
    var wrapper = document.querySelector(selector);
    wrapper.addEventListener("click", initialOverlayClickHandler);
  }
  initButton(".jacketc");
}());

(function iife() {
  "use strict";
  document.querySelector(".jacketc").addEventListener("click", function() {
    document.querySelector(".wrapg").classList.remove("hide");
  });
}());