Conditional Matches

You don’t need the match() and noMatch() functions. They make the upTo() function a little bit easier to understand, but have no other benefit.

What I’m saying is the other way around. That the upTo() function is required and the match/noMatch functions aren’t required.

I think what you’re saying is:

This:

 function upTo(el, selector) {
     while (el.matches(selector) === false) {
       el = el.parentNode;
     }
     return el;
   }

function getPlayButton(el) {
    return upTo(el, ".playButton");
}

Is better than this:


   function upTo(el, selector) {
     while (noMatch(el, selector)) {
       el = el.parentNode;
     }
     return el;
   }

   function upTo(el, selector) {
     while (noMatch(el, selector)) {
       el = el.parentNode;
     }
     return el;
   }

function getPlayButton(el) {
    return upTo(el, ".playButton");
}

The extra code for the match() / noMatch() functions doesn’t provide a significant enough benefit to warrant their inclusion.

If there were other functions other than upTo() that would use match() and noMatch(), then a better justification could be provided to use them, but currently that is not the case.

Can the same be said about:


    while (!hasMatch(el, selector)) {
    }

Yes, that’s right.

The good thing about the code for multiple players, is that it works even when there is only one player too.
The benefit gained there is that it continues to work when moving from a single player to multiple players.

How can you tell if it’s single, or multiple?

If this is multiple:

What would single look like?

We can tell if it’s single or multiple by looking at the HTML code.

If you mean how can the code tell that it’s single or multiple, it doesn’t. Instead, when we use querySelectorAll to get an array-like list of elements in an object called a nodeList.

When we do var buttons = querySelectorAll(...) that buttons variable ends up being a nodeList.

We can use forEach to iterate over each of the elements in that nodeList. If there is only one element in that nodeList then it doesn’t care, it just does that one item, but would be capable of doing multiple ones if they existed too.

1 Like

Just curious, but how would it react if it found no matching elements?

querySelectorAll gives an empty nodeList when no matching elements are found. Using forEach on that empty nodeList doesn’t result in any error either.

When forEach is run on an empty nodeList or an empty array, it just does nothing because it has nothing to do it on.

So, no matching elements is a safe situation that occurs with no error.

1 Like

How come this code doesn’t require a conditional match?


(function iife() {
    "use strict";

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

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

    function playButtonClickHandler() {
        var button = document.querySelector(".playButton2");
        var player = document.querySelector("audio");
        var play = button.querySelector(".play2");
        var pause = button.querySelector(".pause2");
        hide(button.querySelector(".initial2"));
        player.volume = 1.0;
        if (player.paused) {
            hide(play);
            show(pause);
            player.play();
            button.classList.add("active");
        } else {
            show(play);
            hide(pause);
            player.pause();
        }
    }

    function playButtonMouseoverHandler() {
        var button = document.querySelector(".playButton2");
        var player = button.querySelector("audio");
        var speaker = button.querySelector(".speaker2");
        var pause = button.querySelector(".pause2");
        player.isPlaying = function isPaused() {
            return player.paused === false;
        };
        if (player.isPlaying()) {
            hide(speaker);
            show(pause);
        }
    }

    function playButtonMouseoutHandler() {
        var button = document.querySelector(".playButton2");
        var player = button.querySelector("audio");
        var pause = button.querySelector(".pause2");
        var speaker = button.querySelector(".speaker2");
        player.isPlaying = function isPlaying() {
            return player.paused === false;
        };
        if (player.isPlaying()) {
            hide(pause);
            show(speaker);
        }
    }
    var playButton = document.querySelector(".playButton2");
    playButton.addEventListener("click", playButtonClickHandler);
    playButton.addEventListener("mouseover", playButtonMouseoverHandler);
    playButton.addEventListener("mouseout", playButtonMouseoutHandler);
}());

That’s because that code unconditionally gets the first button that it can find on the page.

huh, what do you mean?

The var button line uses querySelector to get the button, which doesn’t care if there are other buttons on the page. Even if there are multiple buttons on the page, querySelector only gives the first one that it can find.

Would it be smart to add this to it?

    function getPlayButton(el) {
      while (el.classList.contains("playButton1") === false) {
        el = el.parentNode;
      }
      return el;
    }

        function playButtonClickHandler(evt) {
      var button = getPlayButton(evt.target);
      togglePlayButton(button);
    }
 (function iife() {
   "use strict";

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

   function hide(el) {
     el.classList.add("hide2");
   }
   
   
   
       function getPlayButton(el) {
      while (el.classList.contains("playButton2") === false) {
        el = el.parentNode;
      }
      return el;
    }

   
   
   

   function playButtonClickHandler() {
     var button = document.querySelector(".playButton2");
     var player = document.querySelector("audio");
     var play = button.querySelector(".play2");
     var pause = button.querySelector(".pause2");
     hide(button.querySelector(".initial2"));
     player.volume = 1.0;
     if (player.paused) {
       hide(play);
       show(pause);
       player.play();
       button.classList.add("active");
     } else {
       show(play);
       hide(pause);
       player.pause();
     }
   }

    function playButtonMouseoverHandler() {
    var button = document.querySelector(".playButton2");
      var player = button.querySelector("audio");
      var speaker = button.querySelector(".speaker2");
      var pause = button.querySelector(".pause2");
      player.isPlaying = function isPaused() {
        return player.paused === false;
      };
      if (player.isPlaying()) {
        hide(speaker);
        show(pause);
      }
    }

    function playButtonMouseoutHandler() {
    var button = document.querySelector(".playButton2");
      var player = button.querySelector("audio");
      var pause = button.querySelector(".pause2");
      var speaker = button.querySelector(".speaker2");
      player.isPlaying = function isPlaying() {
        return player.paused === false;
      };
      if (player.isPlaying()) {
        hide(pause);
        show(speaker);
      }
    }
    
        function playButtonClickHandler(evt) {
      var button = getPlayButton(evt.target);
      togglePlayButton(button);
    }

    
    
    var playButton = document.querySelector(".playButton2");
    playButton.addEventListener("click", playButtonClickHandler);
    playButton.addEventListener("mouseover", playButtonMouseoverHandler);
    playButton.addEventListener("mouseout", playButtonMouseoutHandler);
  }());

It wouldn’t serve any benefit with that code.

oh, really.

How come?

When is it best, and not best to use it?