I'm receiving a "script error"

Leaving it in the code I am able to know what it was before, and if I see it, that will remind me to change it.

That is a widely known bad reason to do so. You are now breaching “good-practice”.

1 Like

So I know, if I see it in older codes, I will know it needs to be changed.

It’s the linter that should tell you that kind of thing. Comments are the wrong way to do that.

2 Likes

Why am I receiving these errors?

  1. Don’t wrap function literals in parens.(function manageCurtain() {

17: 3

  1. Wrap an immediate function invocation in parentheses to assist the reader in understanding that the expression is the result of a function, and not the function itself.})();

https://jsfiddle.net/k703cnzp/

(function manageCurtain() {
  "use strict";

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

  function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    //hide(cover);
    const curtain = document.querySelector(".inner");
    curtain.classList.add("slide");
  }

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

const videoPlayer = (function makeVideoPlayer() {
  "use strict";

  let player = null;

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

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

  function onPlayerStateChange(event) {
    player = event.target;
    const shufflePlaylist = true;

    if (!hasShuffled) {
      player.setShuffle(shufflePlaylist);
      player.playVideoAt(0);
      hasShuffled = true;
    }
  }

  function addPlayer(video) {

    const playlist = "M7lc1UVf-VE";
    const config = {
      height: 393,
      host: "https://www.youtube-nocookie.com",
      width: 699
    };
    config.playerVars = {
      autoplay: 0,
      cc_load_policy: 0,
      controls: 1,
      disablekb: 1,
      fs: 0,
      iv_load_policy: 3,
      loop: 1,
      playlist,
      rel: 0
    };
    config.events = {
      "onReady": onPlayerReady,
      "onStateChange": onPlayerStateChange
    };
    player = new YT.Player(video, config);

  }

  function play() {
    player.playVideo();
  }
  return {
    addPlayer,
    play
  };
}());

function onYouTubeIframeAPIReady() {
  const cover = document.querySelector(".jacketwrap");
  const wrapper = cover.parentElement;
  const frameContainer = wrapper.querySelector(".video");
  videoPlayer.addPlayer(frameContainer);
}

(function iife() {
  "use strict";

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

  function coverClickHandler(evt) {
    const wrapper = evt.currentTarget.parentElement;
    show(wrapper);
    videoPlayer.play();
  }
  const cover = document.querySelector(".jacketwrap");
  cover.addEventListener("click", coverClickHandler);
}());

Fixed:
https://jsfiddle.net/pw8z4aoc/1/


(function manageCurtain() {
    "use strict";

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

    function coverClickHandler(evt) {
    const cover = evt.currentTarget;
    //hide(cover);
    const curtain = document.querySelector(".inner");
    curtain.classList.add("slide");
  }

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

const videoPlayer = (function makeVideoPlayer() {
    "use strict";

    let player = null;

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

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

    function onPlayerStateChange(event) {
        player = event.target;
        const shufflePlaylist = true;

        if (!hasShuffled) {
            player.setShuffle(shufflePlaylist);
            player.playVideoAt(0);
            hasShuffled = true;
        }
    }

    function addPlayer(video) {

        const playlist = "M7lc1UVf-VE";
        const config = {
            height: 393,
            host: "https://www.youtube-nocookie.com",
            width: 699
        };
        config.playerVars = {
            autoplay: 0,
            cc_load_policy: 0,
            controls: 1,
            disablekb: 1,
            fs: 0,
            iv_load_policy: 3,
            loop: 1,
            playlist,
            rel: 0
        };
        config.events = {
            "onReady": onPlayerReady,
            "onStateChange": onPlayerStateChange
        };
        player = new YT.Player(video, config);

    }

    function play() {
        player.playVideo();
    }
    return {
        addPlayer,
        play
    };
}());

function onYouTubeIframeAPIReady() {
    const cover = document.querySelector(".jacketwrap");

    const wrapper = cover.parentElement;
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
}

(function iife() {
    "use strict";

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

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.parentElement;
        show(wrapper);
        videoPlayer.play();
    }

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

Solving that issue brings us closer to the standard module structure of JavaScript code.

Assigning the parenthesised function literal to a variable name, lets us call the code at some later stage.

const manageCurtain = (function makeManageCurtain() {
    ...
}());

That kind of code structure becomes really useful when you have an init function with the code.

We don’t currently have an init function with that code, but some of the code runs automatically when the code is run. That really should be put into an init function instead.

  function init() {
      const cover = document.querySelector(".jacketwrap");
      cover.addEventListener("click", coverClickHandler);
  }

That way, we can return an object from makeManageCover that references the init function, letting us properly initialize manageCover.

const manageCurtain = (function makeManageCurtain() {
    return {
        init
    };
}());
...
manageCurtain.init();

That way instead of the manageCurtain function automatically initializing, it does so under our control when we want it to.

With the videoPlayer code, the onYouTubeIframeAPIReady function really should be a part of the init code instead.

We can move the onYouTubeIframeAPIReady function inside of the videoPlayer function, and add it to the window from an init function.

const videoPlayer = (function makeVideoPlayer() {
  ...
  function onYouTubeIframeAPIReady() {
    const cover = document.querySelector(".jacketwrap");
    const wrapper = cover.parentElement;
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
  }
  function init() {
    window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady;
  }

That way, we can return a reference to the init function, and properly initialize the code when we are ready to do so.

  return {
    addPlayer,
    play,
    init
  };
}());
videoPlayer.init();

Another benefit of using these init methods is that init statements can all be moved down to the end of the code, below all of the functions.

We can do similar with the code that initializes the cover:

const initCover = (function iife() {
  ...
  function init() {
    const cover = document.querySelector(".jacketwrap");
    cover.addEventListener("click", coverClickHandler);
  }
  return {
    init
  };
}());

Letting us do all of the initialization at the bottom of the code, where it belongs.

manageCurtain.init();
videoPlayer.init();
initCover.init();
1 Like

I noticed there was an error in the code I thought was fixed.
I saw an error in jslint.

I fixed it here, now no errors in jslint.
https://jsfiddle.net/rwcgktxy/1/

(function manageCurtain() {
    "use strict";

    function coverClickHandler() {
        const curtain = document.querySelector(".inner");
        curtain.classList.add("slide");
    }

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

const videoPlayer = (function makeVideoPlayer() {
    "use strict";

    let player = null;

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

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

    function onPlayerStateChange(event) {
        player = event.target;
        const shufflePlaylist = true;

        if (!hasShuffled) {
            player.setShuffle(shufflePlaylist);
            player.playVideoAt(0);
            hasShuffled = true;
        }
    }

    function addPlayer(video) {

        const playlist = "M7lc1UVf-VE";
        const config = {
            height: 393,
            host: "https://www.youtube-nocookie.com",
            width: 699
        };
        config.playerVars = {
            autoplay: 0,
            cc_load_policy: 0,
            controls: 1,
            disablekb: 1,
            fs: 0,
            iv_load_policy: 3,
            loop: 1,
            playlist,
            rel: 0
        };
        config.events = {
            "onReady": onPlayerReady,
            "onStateChange": onPlayerStateChange
        };
        player = new YT.Player(video, config);

    }

    function play() {
        player.playVideo();
    }
    return {
        addPlayer,
        play
    };
}());

function onYouTubeIframeAPIReady() {
    const cover = document.querySelector(".jacketwrap");
    const wrapper = cover.parentElement;
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
}

(function iife() {
    "use strict";

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

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.parentElement;
        show(wrapper);
        videoPlayer.play();
    }

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

Are you sure? I still see a JSLint error with that code.

jslint says 0 errors
https://jsfiddle.net/rwcgktxy/1/


(function manageCurtain() {
    "use strict";

    function coverClickHandler() {
        const curtain = document.querySelector(".inner");
        curtain.classList.add("slide");
    }

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

const videoPlayer = (function makeVideoPlayer() {
    "use strict";

    let player = null;

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

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

    function onPlayerStateChange(event) {
        player = event.target;
        const shufflePlaylist = true;

        if (!hasShuffled) {
            player.setShuffle(shufflePlaylist);
            player.playVideoAt(0);
            hasShuffled = true;
        }
    }

    function addPlayer(video) {

        const playlist = "M7lc1UVf-VE";
        const config = {
            height: 393,
            host: "https://www.youtube-nocookie.com",
            width: 699
        };
        config.playerVars = {
            autoplay: 0,
            cc_load_policy: 0,
            controls: 1,
            disablekb: 1,
            fs: 0,
            iv_load_policy: 3,
            loop: 1,
            playlist,
            rel: 0
        };
        config.events = {
            "onReady": onPlayerReady,
            "onStateChange": onPlayerStateChange
        };
        player = new YT.Player(video, config);

    }

    function play() {
        player.playVideo();
    }
    return {
        addPlayer,
        play
    };
}());

function onYouTubeIframeAPIReady() {
    const cover = document.querySelector(".jacketwrap");

    const wrapper = cover.parentElement;
    const frameContainer = wrapper.querySelector(".video");
    videoPlayer.addPlayer(frameContainer);
}

(function iife() {
    "use strict";

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

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.parentElement;
        show(wrapper);
        videoPlayer.play();
    }

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

How can that be? At jslint.com when I select Brower for the environment, it reports when I press the JSLine button that the following problem exists:

1. Undeclared 'YT'.
        player = new YT.Player(video, config);

Ahh I see. You have manually added the global variable YT to the JSLint page before running the linter.

On the instructions page there are details about using the global directive.

That is where you use the following single comment, to give information both to programmers and the linter about global variables that your code expects to be available.

/*global YT */
(function manageCurtain() {

Actually hang on, the same global directives page recommends for self-loading code to just use a var instead.

var YT; // for the self-loading youtube iframe api
(function manageCurtain() {

Aren’t you supposed to add YT manually to jslint?

Was I doing it wrong?

I should be doing this instead?

/*global YT */
(function manageCurtain() {

Yes you can add YT to the linter every time you run up the page, but the comment line there is how you can include that information for the benefit of the linter.

Another important aspect is that it’s for the benefit of any programmer that looks at the code too. It helps to give them information that they didn’t have before, about what’s happening with that global variable that’s used by the code.

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.