Search code examples
javascripthtmlcssqueryselector

Cannot read properties of null (reading 'querySelectorAll') at line 189


That points to this line:

wrappers = container.querySelectorAll(".wrap");

Clicking the exit button causes the error.

Clicking on the exit button is supposed to remove the player, after the blue play button is clicked.

To test jsitor code click run not update.

code https://jsitor.com/KZMNnkSf5

https://jsfiddle.net/e631o2rq/

How is that fixed in the code?

  function removePlayerHandler(evt) {
    const el = evt.target;
    let container = el.closest(".container");
    let wrappers;
    if (container) { //if multiple players
      wrappers = container.querySelectorAll(".remove .wrap");
    } else { //if single player
      container = el.closest(".remove");
      wrappers = container.querySelectorAll(".wrap");
    }
    wrappers.forEach(function (wrapper) {
      if (wrapper.player) {
        removePlayer(wrapper);
      }
    });
  }

It used to look like this:

  function removePlayerHandler(evt) {
    const el = evt.target;
    const container = el.closest(".container");
    const wrapper = container.querySelector(".wrap");
    if (wrapper.player) {
      return removePlayer(wrapper);
    }
  }



        </div>
      </div>
    </div>
  </div>
</div>

 <div class="button-container">
<button class="exit" type="button"></button>
<button class="exit exitpPage2" type="button"></button>
<button class="exit exitpPage3" type="button"></button>
</div>

Solution

  • I'm not entirely sure what you're trying to do here, but it does look a little complicated. I might suggest just keeping things a lot simpler.

    Here's an idea: https://jsitor.com/JOlxKAhhbL

    Code attached below also so it can be read, but due to the sandboxing of iframes in stackoverflow, it fails to load the youtube player, instead, load the jsitor link above.

    // Note: move data-id to `.wrap` element
    
    const DEFAULT_PLAY_OPTIONS = {
      events: {
        onReady: function onPlayerReady(event) {
          event.target.playVideo()
        },
        onStateChange: function onPlayerStateChange(event) {
          // whatever you'd like
        }
      },
      height: 360,
      host: "https://www.youtube-nocookie.com",
      playerVars: {
        autoplay: 1,
        controls: 1,
        disablekb: 1,
        fs: 0,
        iv_load_policy: 3
      },
      width: 640
    }
    const removeAllPlayers = () => {
      for (const wrapperEle of [...document.querySelectorAll('.embed-youtube.active')]) {
        wrapperEle.querySelector('iframe').remove()
        const videoEle = document.createElement('div')
        videoEle.classList.add('video', 'embed-youtube')
        wrapperEle.append(videoEle)
        const curtainEle = wrapperEle.closest('.curtain,.curtain1')
        curtainEle.classList.remove('slide')
        wrapperEle.classList.remove('active')
      }
    }
    const createAndPlayVideo = (playBtnEle) => {
      const curtainEle = playBtnEle.closest('.curtain,.curtain1')
      const wrapperEle = playBtnEle.closest('.wrap')
      const embedYoutubeEle = wrapperEle.querySelector('.video')
      const playOptions = {...DEFAULT_PLAY_OPTIONS}
      playOptions.videoId = wrapperEle.getAttribute('data-id')
      const player = new YT.Player(embedYoutubeEle, playOptions)
      curtainEle.classList.add('slide')
      wrapperEle.classList.add('active')
    }
    const bindPlayers = () => {
      for (const playBtn of [...document.querySelectorAll('.playa')]) {
        playBtn.addEventListener('click', function(clickEvent) {
          createAndPlayVideo(clickEvent.target)
        })
      }
      for (const stopBtn of [...document.querySelectorAll('.exit')]) {
        stopBtn.addEventListener('click', function(clickEvent) {
          removeAllPlayers()
        })
      }
    }
    const init = () => {
      bindPlayers()
    }
    
    init()
    html,
    body {
      height: 100%;
      margin: 0;
      padding: 0;
    }
    
    body {
      background: #302b63;
    }
    
    .button-container {
      display: flex;
      flex-wrap: wrap;
      min-height: 100%;
      margin: auto;
      justify-content: center;
      align-content: center;
      width: 290px;
      gap: 10px;
      background: green;
    }
    
    .container2 .container {
      background: teal;
    }
    
    .container3 .container {
      background: green;
    }
    
    .container1 {
      position: absolute;
      left: 0;
      right: 0;
      min-height: 100%;
      min-width: 255px;
      display: flex;
      padding: 8px 8px;
    }
    
    .curtain1 {
      flex: 1 0 0;
      margin: auto;
      max-width: 640px;
      border: 21px solid;
      border-radius: 12px;
      border-color: #000 #101010 #000 #101010;
      position: relative;
    }
    
    .ratio-keeper {
      position: relative;
      height: 0;
      padding-top: 56.25%;
      margin: auto;
      overflow: hidden;
    }
    
    .container {
      position: absolute;
      left: 0;
      right: 0;
      min-height: 100%;
      padding: 8px 8px;
    }
    
    .curtain {
      margin: auto auto 40px;
      max-width: 640px;
      border: 21px solid;
      border-radius: 12px;
      border-color: #000 #101010 #000 #101010;
      position: relative;
    }
    
    .embed-youtube iframe,
    .embed-youtube .embed-youtube-play,
    .embed-youtube .embed-youtube-play::before {
      position: absolute;
    }
    
    .embed-youtube iframe {
      height: 100%;
      width: 100%;
      top: 0;
      left: 0;
    }
    
    .embed-youtube .embed-youtube-play {
      -webkit-appearance: none;
      appearance: none;
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
      margin: auto;
      display: flex;
      justify-content: center;
      align-items: center;
      width: 90px;
      height: 90px;
      border-radius: 50%;
      cursor: pointer;
      border: 9px solid blue;
      background: transparent;
      filter: drop-shadow(3px 3px 3px #000000b3);
      z-index: 1;
    }
    
    .embed-youtube-play::before {
      content: "";
      width: 0;
      height: 0;
      border-top: 20px solid transparent;
      border-bottom: 20px solid transparent;
      border-left: 27px solid blue;
      transform: translateX(4px);
    }
    
    .embed-youtube-play:hover {
      box-shadow: 0 0 0 5px rgba(43, 179, 20, 0.5);
    }
    
    .embed-youtube-play:focus {
      outline: 0;
      box-shadow: 0 0 0 5px rgba(0, 255, 255, 0.5);
    }
    
    .embed-youtube.active .embed-youtube-play {
      display: none;
    }
    
    @keyframes rotate {
      0% {
        transform: rotate(0deg);
      }
      99.9% {
        border-color: red transparent red transparent;
        pointer-events: none;
      }
      100% {
        transform: rotate(360deg);
        border-color: blue;
      }
    }
    
    @keyframes triangle {
      0% {
        opacity: 0;
      }
      99.9% {
        opacity: 0;
      }
      100% {
        border-left-color: blue;
        opacity: 1;
      }
    }
    
    .exit {
      position: absolute;
      top: auto;
      bottom: -47.63px;
      margin: auto;
      right: 0;
      left: 0;
      width: 47px;
      height: 47px;
      cursor: pointer;
      border-radius: 100%;
      background: transparent;
      border: 5px solid red;
      box-sizing: border-box;
      clip-path: circle(50%);
    }
    
    .exit::before,
    .exit::after {
      content: "";
      background-color: red;
      width: 47px;
      height: 5px;
      position: absolute;
      top: 0px;
      left: -5px;
      right: 0;
      bottom: 0;
      margin: auto;
    }
    
    .exit::before {
      transform: rotate(45deg);
    }
    
    .exit::after {
      transform: rotate(-45deg);
    }
    
    .exit.exitpPage2 {
      position: absolute;
      top: auto;
      bottom: -47.63px;
      margin: auto;
      right: 200px;
      left: 0;
      border: 5px solid blue;
    }
    
    .exit.exitpPage2::before,
    .exit.exitpPage2::after {
      background-color: blue;
    }
    
    .exit.exitpPage3 {
      position: absolute;
      top: auto;
      bottom: -47.63px;
      margin: auto;
      right: 0px;
      left: 200px;
      border: 5px solid purple;
    }
    
    .exit.exitpPage3::before,
    .exit.exitpPage3::after {
      background-color: purple;
    }
    
    .hide {
      display: none;
    }
    <div class="container1">
      <div class="curtain1 remove">
        <div class="ratio-keeper">
          <div class="video-one"></div>
          <div class="wrap embed-youtube" data-id="djV11Xbc914">
            <div class="video embed-youtube ">
            </div>
            <button class="playa cover embed-youtube-play" type="button"></button>
          </div>
        </div>
    
      </div>
    </div>
    <div class="container2 hide">
      <div class="container ">
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-two"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playb cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-three"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playc cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-four"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playd cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-five"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playe cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-six"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playf cover embed-youtube-play" type="button"></button>
            </div>
          </div>
    
        </div>
      </div>
    </div>
    <div class="container3 hide">
      <div class="container ">
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-seven"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playg cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-eight"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playh cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-nine"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playi cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-ten"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playj cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
        <div class="curtain remove">
          <div class="ratio-keeper">
            <div class="video-eleven"></div>
            <div class="wrap embed-youtube">
              <div class="video embed-youtube" data-id="djV11Xbc914">
              </div>
              <button class="playk cover embed-youtube-play" type="button"></button>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <div class="button-container">
      <button class="exit" type="button"></button>
      <button class="exit exitpPage2" type="button"></button>
      <button class="exit exitpPage3" type="button"></button>
    </div>
    <script src="https://www.youtube.com/player_api"></script>