How come .jacketd requires a 2nd ClickHandler?

Setting the code up this way, how come

.jacketc doesn’t need a 2nd ClickHandler,

But .jacketd does?
https://jsfiddle.net/prgw7849/2/

(function iife() {
  "use strict";

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

  function coverClickHandler(evt) {
    const wrapper = evt.currentTarget.nextElementSibling;
    show(wrapper);
  }
  const cover = document.querySelector(".jacketd");
  cover.addEventListener("click", coverClickHandler);
}());
1 Like

One of them hides the cover.
The other one shows the the wrapper.

I’ll delve in to what is appropriate when I return.

The two event handlers for .jacketd are to both hide the jacket, and to show the videos. Here’s how they can be combined into an easy to configure system.

Remove JS load script

The first thing I do when working through the code is to remove the load script. There’s no good reason to have that there at all. A good reason would be if the script names were different each time the page runs. That is not and likely never will be the case, so get rid of it.

In jsFiddle, the https://www.youtube.com/player_api script can be added to the Resources panel instead.

With a separate HTML coding project, you would add a tag before the rest of the scripting code.

<script src="https://www.youtube.com/player_api"></script>
<script src="players.js"></script>

That is much simpler than the unneeded complexity of a separate load script.

Along with removing the load script, we can also remove the code that used it.

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

Remove duplicate cover code

The next thing I see is that you have two sets of manageCover code, that are identical all except for “.jacketc” and “.jacketd”

That code should be updated so that it receives the jacket. That way only one set of manageCover code is ever needed.

Keeping things simple, it can just be a simple function called cover.

// (function manageCover() {
function cover(coverSelector) {
  ...
  // const cover = document.querySelector(".jacketc");
  const cover = document.querySelector(coverSelector);
  cover.addEventListener("click", coverClickHandler);
// }());
}

You can now deal with both covers using that one set of code, with the following statements:

cover(".jacketc");
cover(".jacketd");

Combine the cover code

The above cover code hides the cover, but right at the end of the code there is other cover code that shows wrapper. Those two sets of code are nearly identical. It makes sense to use the same set of code to control those things.

We shouldn’t use cover.hide(".jacketc") though because we are not hiding the jacket. Instead we are setting up a click event so that it will be hidden when it’s clicked. That’s some init stuff that is happening there. Calling it `cover.init(“.jacketc”) makes better sense instead.

We now have a good justification to make the cover code more capable, and return an init function.

// function cover(coverSelector) {
const cover = (function iife() {
  ...
  function init(coverSelector) {
    const cover = document.querySelector(coverSelector);
    cover.addEventListener("click", coverClickHandler);
  }
  return {
    init
  };
// }
}());
// cover(".jacketc");
// cover(".jacketd");
cover.init(".jacketc");
cover.init(".jacketd");

Hiding and showing things

When .jacketd is clicked we want it to show something else. That is too specific a kind of detail to fully put into the function.

One option is to have separate show and hide methods, but we aren’t really wanting to show the jacket. Instead, clicking on a jacket causes something else to be shown instead.

That means passing a set of options, so that when a jacket is clicked, other things can be triggered to happen too.

We still want the cover code to have a show function:

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

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

As for the rest of it, we can add an options object on which we add a show selector. Here’s how it could look in the end:

cover.init(".jacketc");
cover.init(".jacketd", {
  show: ".wraph"
});

The init function needs to accept an optional options parameter. I’ll give it a default value as an empty object, to help aid usability.

  // function init(coverSelector) {
  function init(coverSelector, initOptions = {}) {

Later on when the click event occurs, it needs to know what those options are, so we can add those to the cover that’s being initialized.

  function init(coverSelector, options = {}) {
    const cover = document.querySelector(coverSelector);
    cover.showSelector = options.show;
    cover.hideSelector = options.hide;
    cover.addEventListener("click", coverClickHandler);
  }

Now from the clickHandler code, we can check for showSelector and hideSelector, and do something based on them.

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    hide(cover);
    const showEl = document.querySelector(cover.showSelector);
    if (showEl) {
      show(showEl);
    }
    const hideEl = document.querySelector(cover.hideSelector);
    if (hideEl) {
      hide(hideEl);
    }
  }

Make things smarter

That’s not quite good enough though. The event handler really should only pick up information and pass it on to somewhere else.

Instead, we can just blindly pass those showSelector and hideSelector elements to the show and hide functions.

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    hide(cover);
    show(document.querySelector(cover.showSelector));
    hide(document.querySelector(cover.hideSelector));
  }

We can now make the show and hide functions a little bit smarter.

  function show(el) {
    if (!el) {
      return;
    }
    el.classList.remove("hide");
  }
  function hide(el) {
    if (!el) {
      return;
    }
    el.classList.add("hide");
  }

Using the improved cover

We can now easily show other things when the jacket is clicked.

cover.init(".jacketc");
cover.init(".jacketd", {
  show: ".wraph"
});

Not only can we show other things, but the ability is there to support hiding other things too.

Later on if multiple things want to be added or hidden, it only takes a small improvement to the cover function to support that too.

Summary

With functions, it’s best when different configurations don’t end up changing the internal workings of the code.

That’s what function parameters are there for, to let you easily configure and change what the code does on an as-needed basis without needing to fiddle with the inner workings of the function itself.

The updated cover code is:

const cover = (function iife() {
  "use strict";

  function show(el) {
    if (!el) {
      return;
    }
    el.classList.remove("hide");
  }
  function hide(el) {
    if (!el) {
      return;
    }
    el.classList.add("hide");
  }
  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    hide(cover);
    show(document.querySelector(cover.showSelector));
    hide(document.querySelector(cover.hideSelector));
  }

  function init(coverSelector, options = {}) {
    const cover = document.querySelector(coverSelector);
    cover.showSelector = options.show;
    cover.hideSelector = options.hide;
    cover.addEventListener("click", coverClickHandler);
  }
  return {
    init
  };
}());

...

cover.init(".jacketc");
cover.init(".jacketd", {
  show: ".wraph"
});

The updated code is found at https://jsfiddle.net/em62d49L/1/ and if you scroll to the bottom of the code, you’ll find the cover inits are at line 128, between the functions and the code that inits the playlists.

2 Likes

95 posts were split to a new topic: What is the purpose of the load function?