Clicking one element to remove a different element

Would you recommend that I change all “vars” to “const,” as I did here?

I put everything in notepad and replaced all the “vars” with “const.”

Good, or bad?

jslint says there are no errors in the code.

(function iife() {
    "use strict";

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

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

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

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", initialOverlayClickHandler);
    }
    initButton(".jacketa");
}());
(function iife() {
    "use strict";
    document.querySelector(".jacketa").addEventListener("click", function() {
        document.querySelector(".container").classList.remove("hide");
    });
}());
(function iife() {
    "use strict";

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

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

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

    function hideAllButtons(button) {
        button.querySelectorAll(".play, .pause, .speaker").forEach(hide);
    }

    function getPlay(button) {
        return button.querySelector(".play");
    }

    function getPause(button) {
        return button.querySelector(".pause");
    }

    function showPlayButton(button) {
        const play = getPlay(button);
        hideAllButtons(button);
        show(play);
        button.classList.remove("active");
    }

    function isPlaying(button) {
        const play = getPlay(button);
        return play.classList.contains("hide");
    }

    function pauseAllButtons() {
        const buttons = document.querySelectorAll(".playButton");
        buttons.forEach(function hidePause(button) {
            if (isPlaying(button)) {
                showPlayButton(button);
            }
        });
    }

    function showPauseButton(button) {
        const pause = getPause(button);
        pauseAllButtons();
        hideAllButtons(button);
        show(pause);
        button.classList.add("active");
    }

    function getAudio() {
        return document.querySelector("audio");
    }

    function playAudio(player, src) {
        player.volume = 1.0;
        if (player.getAttribute("src") !== src) {
            player.setAttribute("src", src);
        }
        player.play();
    }

    function showButton(button, opts) {
        if (opts.playing) {
            showPlayButton(button);
        } else {
            showPauseButton(button);
        }
    }

    function pauseAudio(player) {
        player.pause();
    }

    function manageAudio(player, opts) {
        if (opts.playing) {
            pauseAudio(player);
        } else {
            playAudio(player, opts.src);
        }
    }

    function togglePlayButton(button) {
        const player = getAudio();
        const playing = isPlaying(button);
        showButton(button, {
            playing
        });
        manageAudio(player, {
            src: button.getAttribute("data-audio"),
            playing
        });
    }

    function playButtonClickHandler(evt) {
        const button = getButtonContainer(evt.target);
        togglePlayButton(button);
    }

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", playButtonClickHandler);
    }
    initButton(".wrapa");
}());
(function iife() {
    "use strict";

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

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

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

    function initButton(selector) {
        const 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");
    });
}());
(function iife() {
    "use strict";
    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) {
        const youtubePlayer = event.target;
        youtubePlayer.setVolume(100); // percent
    }
    window.onYouTubePlayerAPIReady = function() {
        new YT.Player(document.querySelector(".js-player"), {
            events: {
                "onReady": onPlayerReady
            }
        });
    };
}());
(function iife() {
    "use strict";

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

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

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

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", initialOverlayClickHandler);
    }
    initButton(".jacketd");
}());
(function iife() {
    "use strict";
    document.querySelector(".jacketd").addEventListener("click", function() {
        document.querySelector(".wraph").classList.remove("hide");
    });
}());
(function iife() {
    "use strict";

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

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

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

    function hideAllButtons(button) {
        button.querySelectorAll(".play, .pause, .speaker").forEach(hide);
    }

    function getPlay(button) {
        return button.querySelector(".play ");
    }

    function getPause(button) {
        return button.querySelector(".pause");
    }

    function getSpeaker(button) {
        return button.querySelector(".speaker");
    }

    function showPlayButton(button) {
        const play = getPlay(button);
        hideAllButtons(button);
        show(play);
        button.classList.remove("active");
    }

    function isPlaying(button) {
        const play = getPlay(button);
        return play.classList.contains("hide");
    }

    function pauseAllButtons() {
        const buttons = document.querySelectorAll(".playButton");
        buttons.forEach(function hidePause(button) {
            if (isPlaying(button)) {
                showPlayButton(button);
            }
        });
    }

    function showPauseButton(button) {
        const pause = getPause(button);
        pauseAllButtons();
        hideAllButtons(button);
        show(pause);
        button.classList.add("activated");
    }

    function showSpeakerButton(button) {
        const speaker = getSpeaker(button);
        hideAllButtons(button);
        show(speaker);
    }

    function getAudio() {
        return document.querySelector("audio");
    }

    function playAudio(player, src) {
        player.volume = 1.0;
        if (player.getAttribute("src") !== src) {
            player.setAttribute("src", src);
        }
        player.play();
    }

    function showButton(button, opts) {
        if (opts.playing) {
            showPlayButton(button);
        } else {
            showPauseButton(button);
        }
    }

    function pauseAudio(player) {
        player.pause();
    }

    function manageAudio(player, opts) {
        if (opts.playing) {
            pauseAudio(player);
        } else {
            playAudio(player, opts.src);
        }
    }

    function playButton(button) {
        const player = getAudio();
        const playing = isPlaying(button);
        showButton(button, {
            playing
        });
        manageAudio(player, {
            src: button.getAttribute("data-audio"),
            playing
        });
    }

    function showPause(button) {
        if (isPlaying(button)) {
            showPauseButton(button);
        }
    }

    function showSpeaker(button) {
        if (isPlaying(button)) {
            showSpeakerButton(button);
        }
    }

    function playButtonClickHandler(evt) {
        const button = getButtonContainer(evt.target);
        playButton(button);
    }

    function playButtonMouseoverHandler(evt) {
        const button = getButtonContainer(evt.target);
        showPause(button);
    }

    function playButtonMouseoutHandler(evt) {
        const button = getButtonContainer(evt.target);
        showSpeaker(button);
    }

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", playButtonClickHandler);
        wrapper.addEventListener("mouseover", playButtonMouseoverHandler);
        wrapper.addEventListener("mouseout", playButtonMouseoutHandler);
    }
    initButton(".wrapb");
}());
(function iife() {
    "use strict";

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

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

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

    function hideAllButtons(button) {
        button.querySelectorAll(".play, .pause, .speaker").forEach(hide);
    }

    function getPlay(button) {
        return button.querySelector(".play");
    }

    function getPause(button) {
        return button.querySelector(".pause");
    }

    function showPlayButton(button) {
        const play = getPlay(button);
        hideAllButtons(button);
        show(play);
        button.classList.remove("active");
    }

    function isPlaying(button) {
        const play = getPlay(button);
        return play.classList.contains("hide");
    }

    function pauseAllButtons() {
        const buttons = document.querySelectorAll(".playButton");
        buttons.forEach(function hidePause(button) {
            if (isPlaying(button)) {
                showPlayButton(button);
            }
        });
    }

    function showPauseButton(button) {
        const pause = getPause(button);
        pauseAllButtons();
        hideAllButtons(button);
        show(pause);
    }

    function getAudio() {
        return document.querySelector("audio");
    }

    function playAudio(player, src) {
        player.volume = 1.0;
        if (player.getAttribute("src") !== src) {
            player.setAttribute("src", src);
        }
        player.play();
    }

    function showButton(button, opts) {
        if (opts.playing) {
            showPlayButton(button);
        } else {
            showPauseButton(button);
        }
    }

    function pauseAudio(player) {
        player.pause();
    }

    function manageAudio(player, opts) {
        if (opts.playing) {
            pauseAudio(player);
        } else {
            playAudio(player, opts.src);
        }
    }

    function playButton(button) {
        const player = getAudio();
        const playing = isPlaying(button);
        showButton(button, {
            playing
        });
        manageAudio(player, {
            src: button.getAttribute("data-audio"),
            playing
        });
    }

    function playButtonClickHandler(evt) {
        const button = getButtonContainer(evt.target);
        playButton(button);
    }

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", playButtonClickHandler);
    }
    initButton(".wrapc");
}());
(function iife() {
    "use strict";

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

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

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

    function hideAllButtons(button) {
        button.querySelectorAll(".play, .pause, .speaker").forEach(hide);
    }

    function getPlay(button) {
        return button.querySelector(".play");
    }

    function getPause(button) {
        return button.querySelector(".pause");
    }

    function showPlayButton(button) {
        const play = getPlay(button);
        hideAllButtons(button);
        show(play);
        button.classList.remove("active");
    }

    function isPlaying(button) {
        const play = getPlay(button);
        return play.classList.contains("hide");
    }

    function pauseAllButtons() {
        const buttons = document.querySelectorAll(".playButton");
        buttons.forEach(function hidePause(button) {
            if (isPlaying(button)) {
                showPlayButton(button);
            }
        });
    }

    function showPauseButton(button) {
        const pause = getPause(button);
        pauseAllButtons();
        hideAllButtons(button);
        show(pause);
    }

    function getAudio() {
        return document.querySelector("audio");
    }

    function playAudio(player, src) {
        player.volume = 1.0;
        if (player.getAttribute("src") !== src) {
            player.setAttribute("src", src);
        }
        player.play();
    }

    function showButton(button, opts) {
        if (opts.playing) {
            showPlayButton(button);
        } else {
            showPauseButton(button);
        }
    }

    function pauseAudio(player) {
        player.pause();
    }

    function manageAudio(player, opts) {
        if (opts.playing) {
            pauseAudio(player);
        } else {
            playAudio(player, opts.src);
        }
    }

    function togglePlayButton(button) {
        const player = getAudio();
        const playing = isPlaying(button);
        showButton(button, {
            playing
        });
        manageAudio(player, {
            src: button.getAttribute("data-audio"),
            playing
        });
    }

    function playButtonClickHandler(evt) {
        const button = getButtonContainer(evt.target);
        togglePlayButton(button);
    }

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", playButtonClickHandler);
    }
    initButton(".wrapd");
}());
(function iife() {
    "use strict";

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

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

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

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", initialOverlayClickHandler);
    }
    initButton(".jacketb");
}());
(function iife() {
    "use strict";
    document.querySelector(".jacketb").addEventListener("click", function() {
        document.querySelector(".wrape").classList.remove("hide");
    });
}());
(function iife() {
    "use strict";

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

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

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

    function hideAllButtons(button) {
        button.querySelectorAll(".play, .pause, .speaker").forEach(hide);
    }

    function getPlay(button) {
        return button.querySelector(".play");
    }

    function getPause(button) {
        return button.querySelector(".pause");
    }

    function showPlayButton(button) {
        const play = getPlay(button);
        hideAllButtons(button);
        show(play);
        button.classList.remove("active");
    }

    function isPlaying(button) {
        const play = getPlay(button);
        return play.classList.contains("hide");
    }

    function pauseAllButtons() {
        const buttons = document.querySelectorAll(".playButton");
        buttons.forEach(function hidePause(button) {
            if (isPlaying(button)) {
                showPlayButton(button);
            }
        });
    }

    function showPauseButton(button) {
        const pause = getPause(button);
        pauseAllButtons();
        hideAllButtons(button);
        show(pause);
    }

    function getAudio() {
        return document.querySelector("audio");
    }

    function playAudio(player, src) {
        player.volume = 1.0;
        if (player.getAttribute("src") !== src) {
            player.setAttribute("src", src);
        }
        player.play();
    }

    function showButton(button, opts) {
        if (opts.playing) {
            showPlayButton(button);
        } else {
            showPauseButton(button);
        }
    }

    function pauseAudio(player) {
        player.pause();
    }

    function manageAudio(player, opts) {
        if (opts.playing) {
            pauseAudio(player);
        } else {
            playAudio(player, opts.src);
        }
    }

    function togglePlayButton(button) {
        const player = getAudio();
        const playing = isPlaying(button);
        showButton(button, {
            playing
        });
        manageAudio(player, {
            src: button.getAttribute("data-audio"),
            playing
        });
    }

    function playButtonClickHandler(evt) {
        const button = getButtonContainer(evt.target);
        togglePlayButton(button);
    }

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", playButtonClickHandler);
    }
    initButton(".wrape");
}());
(function iife() {
    "use strict";

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

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

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

    function hideAllButtons(button) {
        button.querySelectorAll(".play, .pause, .speaker").forEach(hide);
    }

    function getPlay(button) {
        return button.querySelector(".play");
    }

    function getPause(button) {
        return button.querySelector(".pause");
    }

    function showPlayButton(button) {
        const play = getPlay(button);
        hideAllButtons(button);
        show(play);
        button.classList.remove("active");
    }

    function isPlaying(button) {
        const play = getPlay(button);
        return play.classList.contains("hide");
    }

    function pauseAllButtons() {
        const buttons = document.querySelectorAll(".playButton");
        buttons.forEach(function hidePause(button) {
            if (isPlaying(button)) {
                showPlayButton(button);
            }
        });
    }

    function showPauseButton(button) {
        const pause = getPause(button);
        pauseAllButtons();
        hideAllButtons(button);
        show(pause);
    }

    function getAudio() {
        return document.querySelector("audio");
    }

    function playAudio(player, src) {
        player.volume = 1.0;
        if (player.getAttribute("src") !== src) {
            player.setAttribute("src", src);
        }
        player.play();
    }

    function showButton(button, opts) {
        if (opts.playing) {
            showPlayButton(button);
        } else {
            showPauseButton(button);
        }
    }

    function pauseAudio(player) {
        player.pause();
    }

    function manageAudio(player, opts) {
        if (opts.playing) {
            pauseAudio(player);
        } else {
            playAudio(player, opts.src);
        }
    }

    function togglePlayButton(button) {
        const player = getAudio();
        const playing = isPlaying(button);
        showButton(button, {
            playing
        });
        manageAudio(player, {
            src: button.getAttribute("data-audio"),
            playing
        });
    }

    function playButtonClickHandler(evt) {
        const button = getButtonContainer(evt.target);
        togglePlayButton(button);
    }

    function initButton(selector) {
        const wrapper = document.querySelector(selector);
        wrapper.addEventListener("click", playButtonClickHandler);
    }
    initButton(".wrapf");
}());

Yes.

1 Like

You could do it that way, but then you need a separate variable for the player that must be allowed to be changed.

let player;
// overlay code, which uses player to start playing
// youtube code, which assigns the player

Things with the above code seem to be backwards, where you initialize a player variable with no value, have the overlay code which uses it, but not yet, because player isn’t yet defined, and then have the youtube code which sets the player variable, after which the overlay can then use the player variable.

That’s all problematic.

A cleaner solution is to instead have the youtube code supply the player.

const player = youtube code
// then overlay code which uses the player
1 Like

We’ll do the cleaner solution then, and I’ll see how that looks.

This is the whole code:

YouTube Code
Overlay Cover

Everything is inside:

(function iife() {
  "use strict";
}());

This is the one we’ll be making changes to:

This one is separated,
using the init button on the Overlay Cover

YouTube Code
Overlay Cover

YouTube Code

(function iife() {
    "use strict";
}());

Overlay Cover

(function iife() {
  "use strict";
}());

(function iife() {
  "use strict";
  });
}());

Update:

I’m thinking of using this one because it is way less 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
      }
    });
  };

  const show = (el) => el.classList.remove("hide");
  const hide = (el) => el.classList.add("hide");

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

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

What are the differences between these 2 statements,
and how do you know which one gets used?

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

And I assume I’d be using this one:
let player = {};

I think I understand it now,

Because there’s a statement underneath the “let player,”
then this gets added on next to it = {};

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

But the code works without = {}; added on,
so now I’m not even sure if it’s needed or necessary.

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

Should this code use

2 stricts,

(function iife() {
  "use strict";

or is only one necessary here?

I’m in the process of having the youtube code supply the player.


And #26 if you can explain that.

You have it written like this:
let player; 11#

But in the jsfiddle you provided:
https://jsfiddle.net/zb6mkug3/147/

It’s written like this:
let player = {};

Which should it be?


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

/*(function iife() {
  "use strict";*/

  const show = (el) => el.classList.remove("hide");
  const hide = (el) => el.classList.add("hide");

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

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

There is only one event handler attached to the element and it adds the hide class to the element.
Once the element is hidden I believe that the event handler is no longer valid and even if it were it would have no effect as it would only be trying to add the hide class to the classList.
You could try to toggle it instead of adding, but if my first statement is true it will have no effect as it would not be active.
If it toggles from visible to hidden but not the reverse that will show that the toggle works but is blocked when the element is hidden.
Or add the event listener to the iFrame body tag, that should do the trick, I think.

I also have another question:

These are all of them:

1.) Is 1 strict suitable here, or split them into 2?

2.) let player; or let player = {};

the forum #11 said let player; jsfiddle said: let player = {};

Just a clarification on which it should be.

3.) How come you removed const from here? #11

or, was I supposed to put it in as const?

What were you telling me when you put that in there as a note?
What were you saying?

Is const being used in the code, or is it not?
And if it’s not, how come it’s not needed, or necessary here?

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

The code I’m using:


(function iife() {
  "use strict";

  let player = {};
 // 1.) or 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) {
 // const player = event.target;
    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
      }
    });
  };
  // 2.) I'm either using 1 script or 2. 
  
/*}());*/

/*(function iife() {
  "use strict";*/

  const show = (el) => el.classList.remove("hide");
  const hide = (el) => el.classList.add("hide");

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

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

Yes, strict mode is beneficial. Modules automatically enable strict mode, but as your intended usage doesn’t allow modules, strict mode helps to keep JSlint happier about things, and your code behaves more reliably.

That won’t be needed at all when a callback is used.

It should be without the assignment, as it’s an element that’s intended to be there, not an object.

When a variable is going to change (not normally a good thing), you cannot use const, so let must be used instead. We can use a callback to remove the need for that variable at all.

Should this use 2 iife’s, or only 1 is needed / necessary?

Should 1 be utilized here, meaning 1 is sufficient enough,
or should there be 2?

(function iife() {
  "use strict";
(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'm either using 1 iife or 2. 
  
/*}());*/

/*(function iife() {
  "use strict";*/

  const show = (el) => el.classList.remove("hide");
  const hide = (el) => el.classList.add("hide");

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

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

One is enough, however the iife’s do serve a purpose.

// generic code wrapper
(function iife() {
    ...
}());

When they contain information that should remain separated, they don’t need to be called iife. They can be called meaningful names such as userValidation and formTabs instead, so that the name has meaning in regard to what the code is supposed to do.

When it doesn’t make sense to put it all in one, give them a meaningful name instead.

// named code wrappers
(function userValidation() {
    ...
}());
(function formTabs() {
    ...
}());
1 Like

In the process of having the youtube code supply the player, what comes next?
What are the next steps?


(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) {
 // const player = event.target;
    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
      }
    });
  };

  const show = (el) => el.classList.remove("hide");
  const hide = (el) => el.classList.add("hide");

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

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

With the youtube player using a callback, we define a callback that accepts the player and gives it to the lines code.

function linesCallback(player) {
    lines.init(player);
}

Organise the code

We just need to have lines use an init function so that we can later on use that to give information to the hideLines function. To best achieve that, I’ll separate the code into a different sections:

(function hideLines() {
  "use strict";
  const lines = document.querySelector(".wrapg .lines");

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

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

Give player to the click handler

It helps here to start from the desired end-result, of passing player to the click handler.
We can use a click wrapper, so that player is given to the wrapper, and the click handler can then get the player from that wrapper.

and we want to give those lines an init section, to which we can give the player.

  function clickHandler(evt, player) {
    hideLines(evt.target);
    player.playVideo();
  }
  function clickWrapper(player) {
  	return function wrapper(evt) {
      clickHandler(evt, player);
    }
  }
  lines.addEventListener("click", clickWrapper(player));

This way, the event listener uses the returned wrapper function, which retains knowledge of the player variable and gives it to the clickHandler.

Give player to an init function

The click handler is now properly sorted out, and we have moved the problem up to the next level.
That problem now being how do we get the player variable to the addEventListener code. The solution to that is to put the code in an init function, which we can then return to make available, along with the hideLines function:

    function init(player) {
        lines.addEventListener("click", clickWrapper(player));
    }
    return {
        hideLines,
        init
    };

We can then use that from the youTube function, as is seen at https://jsfiddle.net/706vjof3/5/

Remove the global player variable

But we’re not done yet, until the need for that locally global variable is gone for good.
In this case, it’s as easy as moving the player variable into the APIReady function instead:

// let player;
...
        // new YT.Player(document.querySelector(".js-player"), {
        const player = new YT.Player(document.querySelector(".js-player"), {
        ...
        manageLines.init(player);

Previously the lines code assumed that the player variable was globally accessible. By removing that assumption from the lines code, we’ve been able to achieve the benefit of no longer needing to have a globally accessible player variable.

You can find the updated code at https://jsfiddle.net/706vjof3/7/

2 Likes

Oh yes, and the other objective was to use a callback.

Use a callback for better separation of concerns

We don’t want to force the youtubePlayer code to know anything about what’s outside of the youtubePlayer code. Instead, an init function helps us to give information to it when we’re ready.

// (function youtubePlayer() {
const youtubePlayer = (function youtubePlayer(callback) {
        // 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 init() {
        const tag = document.createElement("script");
        tag.src = "https://www.youtube.com/player_api";
        const firstScriptTag = document.getElementsByTagName("script")[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

        window.onYouTubePlayerAPIReady = function APIReady() {
            ...
        };
    }
    return {
        init
    };
}());
youtubePlayer.init();

Give a callback to the youtubePlayer init function

We can now give that init function the callback that we’ll use to start the hideLines code.

        // manageLines.init(player);
        callback(player);
...
    // function init() {
    function init(callback) {
}());
youtubePlayer.init(manageLines.init);

This way the youTubePlayer code doesn’t need to know anything about manageLines or what to do with them. All it needs to care about is passing the player variable to whatever callback that we gave to it, which helps us to make the code easier for us to configure and behave the way that we want.

The updated code is at https://jsfiddle.net/706vjof3/9/

A beneficial side-effect of enforcing the use of const, is that the structure of our code is forced to improve too.

2 Likes

If I’m not using lines then it would stay like this?

The YouTube Code would either come 1st, or it would come 2nd.

Which should it be?

The YouTube script comes first here:

This is the 2nd version

(function iife() {
  "use strict";

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

  const show = (el) => el.classList.remove("hide");
  const hide = (el) => el.classList.add("hide");

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

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

}());

The YouTube script comes second here:

or would the jacket go on top of the YouTube code?


(function iife() {
  "use strict";

  const show = (el) => el.classList.remove("hide");
  const hide = (el) => el.classList.add("hide");

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

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

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

}());

When properly done it doesn’t matter which order, for you just need them to be defined first before you use them.

If the order doesn’t matter, we can then order them or other reasons, and the order in which we see them when normally using the page, is a good way to order them. Overlay first, then lines, then player.

1 Like

Would you suggest I add “function youtubePlayer” separating the two?

Or would it really not be needed, or necessary on this one because there are no lines?
It’s just an overlay cover, and that’s it.

i.e., Should the Overlay remain separated from the YouTube Script?

In this case I don’t think there’s a reason for them to remain separated.
The way the code is set up is fine as it is.

1.) Would I be right?

2.) My second question is:

Is there a difference between

“function iife” and “function anynameatall”

Is there any significance given to “iife” than if you would’ve given it a different name instead?

or there is no significance at all, and it doesn’t matter what it’s called?

i.e: Does the browser treat iife differently than if it was called a different name?

(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");
    const hide = (el) => el.classList.add("hide");

    function coverClickHandler(evt) {
        const cover = evt.currentTarget;
        const thewrap = cover.parentNode.querySelector(".wrap");
        hide(cover);
        show(thewrap);
    }
    const cover = document.querySelector(".jacket ");
    cover.addEventListener("click", coverClickHandler);

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

Yes it should remain separate.

Only in that the immediately invoked function expression is called iife. When there’s a better name that usefully represents what the code does, give it that other name.

I recommend that the code uses the following pattern, for this pattern makes it easier to do beneficial things.

const someName = (function someName() {
    const localVariable = ...
    ...

    function someFunction() {
        ...
    }
    ...
    function init() {
        ...
    }
    return { // restrict only to functions that should be accessed from outside
        someFunction,
        ...
        init
    };
}());
someName.init();
1 Like

You said it should remain separate so I’ll separate them here:

I just added in the “youtubePlayer function” separating them.

Function iife which is the immediate function that comes first:

(function iife() {
    "use strict";

Followed by the YouTube player function which comes after.

(function youtubePlayer() {
    "use strict";

(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");
    const hide = (el) => el.classList.add("hide");

    function coverClickHandler(evt) {
        const cover = evt.currentTarget;
        const thewrap = cover.parentNode.querySelector(".wrap");
        hide(cover);
        show(thewrap);
    }
    const cover = document.querySelector(".jacket ");
    cover.addEventListener("click", coverClickHandler);
}());
(function youtubePlayer() {
    "use strict";
    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) {
        const youtubePlayer = event.target;
        youtubePlayer.setVolume(100); // percent
    }
    window.onYouTubePlayerAPIReady = function() {
        new YT.Player(document.querySelector(".js-player"), {
            events: {
                "onReady": onPlayerReady
            }
        });
    };
}());