YouTube videos aren't appearing after 1 Click

Why is it taking 2 clicks for the YouTube videos to appear?

How would I fix this code so that the players open up right away? It’s taking 2 mouse clicks for them to open. How would I fix that? The videos should open up right away and they are not, how come, and how would I be able to get them to?

This code should be working, and it’s not for some reason. I cannot figure out what is wrong, and how I would get it working right.

The videos should be appearing on 1 click, and not 2. I can’t figure out how to fix this.

Code:
https://jsfiddle.net/hzyrfkwb/50/


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

    function loadPlayer() {
        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.setVolume(50); // percent
    }

    function onPlayerStateChange(event) {
        const player = event.target;
        if (event.data === YT.PlayerState.PLAYING) {
            const otherVideos = (video) => video !== player;
            const pauseVideo = (video) => video.pauseVideo();
            players.filter(otherVideos).forEach(pauseVideo);
        }
        const playerVars = player.b.b.playerVars;
        if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
            player.seekTo(playerVars.start);
        }
    }

    function addVideo(video, desiredPlayerVars) {
        const videoId = video.getAttribute("data-id");
        const defaultPlayerVars = {
            autoplay: 1,
            controls: 1,
            showinfo: 1,
            rel: 0,
            iv_load_policy: 3,
            cc_load_policy: 0,
            fs: 0,
            disablekb: 1
        };
        const playerVars = Object.assign(defaultPlayerVars, desiredPlayerVars);
        players.push(new YT.Player(video, {
            width: 200,
            height: 200,
            videoId: videoId,
            playerVars,
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        }));
    }

    function init(opts) {
        loadPlayer();
        addVideo(opts.video);
    }
    return {
        init
    };
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 900,
                end: 1200
            }
        });
    }
    const cover = document.querySelector(".playa");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playb");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playc");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playd");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playe");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playf");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playg");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playh");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playi");
    cover.addEventListener("click", coverClickHandler);
}());

Seems like the YT variable is not getting initialized before the initial click, resulting in console error: “YT is not defined”

The player_api is loaded by programatically creating a script element on click. (your code below)
On the first click the resources aren’t available in time to play the video. See errors on console

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

By the second click, player_api is already loaded and available. It appears to me that you might be creating a new duplicate script element on every click.

You might consider…

  • You could call loadPlayer() so it runs once on page load. Then it would be available for the first click and all thereafter.
  • You could have the rest of your click handler code wait until the player_api finishes loading
  • Or you could just hardcode that into your HTML skipping any javascript that loads that api altogether
<script type="text/javascript" src="https://www.youtube.com/player_api"></script>

I tried the hardcode option (commenting out body of loadPlayer() also ) on your fiddle and it seemed to work.

1 Like

Could you provide a jsfiddle of how these 2 examples would be done?

  • You could call loadPlayer() so it runs once on page load. Then it would be available for the first click and all thereafter.

  • You could have the rest of your click handler code wait until the player_api finishes loading

Unless there is some reason I think the hardcoded script in HTML is the way to go. If they’re all YouTube videos then you already know the endpoint and that shouldn’t change. Even if you had more than one video API reloading on every click is too much.

Could you provide a jsfiddle showing this?

The iife is first thing in javascript

https://jsfiddle.net/alhazen1/hzyrfkwb/103/

What if I did it this way, would this be better?
https://jsfiddle.net/hzyrfkwb/107/

function init(opts) {
    addVideo(opts.video, opts.playerVars || {});
}
loadPlayer();
return {
    init
};
}());

No, that gets called on every click too.

All loadPlayer does is programatically write

<script type="text/javascript" src="https://www.youtube.com/player_api"></script>

into your html document.

1 Like

Wait a second.

If I’m using this:
<script type="text/javascript" src="https://www.youtube.com/player_api"></script>

Then this:

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

And This:

loadPlayer();

Can be deleted / removed from the code

Am I right?

Those are no-longer needed or necessary.

Code
https://jsfiddle.net/hzyrfkwb/130/

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

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

    function onPlayerStateChange(event) {
        const player = event.target;
        if (event.data === YT.PlayerState.PLAYING) {
            const otherVideos = (video) => video !== player;
            const pauseVideo = (video) => video.pauseVideo();
            players.filter(otherVideos).forEach(pauseVideo);
        }
        const playerVars = player.b.b.playerVars;
        if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
            player.seekTo(playerVars.start);
        }
    }

    function addVideo(video, desiredPlayerVars) {
        const videoId = video.getAttribute("data-id");
        const defaultPlayerVars = {
            autoplay: 1,
            controls: 1,
            showinfo: 1,
            rel: 0,
            iv_load_policy: 3,
            cc_load_policy: 0,
            fs: 0,
            disablekb: 1
        };
        const playerVars = Object.assign(defaultPlayerVars, desiredPlayerVars);
        players.push(new YT.Player(video, {
            width: 200,
            height: 200,
            videoId: videoId,
            playerVars,
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        }));
    }

    function init(opts) {
     addVideo(opts.video, opts.playerVars || {});
        
    }
    return {
        init
    };
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 900,
                end: 1200
            }
        });
    }
    const cover = document.querySelector(".playa");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playb");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playc");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playd");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playe");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playf");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playg");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playh");
    cover.addEventListener("click", coverClickHandler);
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars: {
                start: 30,
                end: 50
            }
        });
    }
    const cover = document.querySelector(".playi");
    cover.addEventListener("click", coverClickHandler);
}());

Correct! Unless you have a reason for not doing that it would be the way to go

1 Like

Thank you for your help.

I’m trying to get the ‘player_api’ script to work with a single player
https://jsfiddle.net/hzyrfkwb/158/

Using this:
<script type="text/javascript" src="https://www.youtube.com/player_api"></script>

I’m confused on how this would be done.

The only thing I’m having trouble getting to work is the html part.

(function iife() {
  "use strict";

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

  function onPlayerStateChange(event) {
    const player = event.target;
    const playerVars = player.b.b.playerVars;
    if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
      player.seekTo(playerVars.start);
    }
  }

  window.onYouTubePlayerAPIReady = function() {
    const video = document.querySelector(".video");
    const videoId = video.getAttribute("data-id");
    new YT.Player(video, {
      width: 606,
      height: 344,
      videoId: videoId,
      playerVars: {
        autoplay: 1,
        controls: 1,
        showinfo: 1,
        rel: 0,
        iv_load_policy: 3,
        cc_load_policy: 0,
        fs: 0,
        disablekb: 1,
        loop: true,
        start: 200,
        end: 204
      },
      events: {
        "onReady": onPlayerReady,
        "onStateChange": onPlayerStateChange
      }
    });
  };
}());

This one uses multiple players:
https://jsfiddle.net/hzyrfkwb/130/

I’m not really sure what you want. You had a problem with errors and delays because you were waiting for a script to load on every click. Now you have the script loaded as your page loads and the problem is gone. Is there something that is not operating properly? All 9 video players seemed to work fine.

player_api is just a short snippet of javascript and all the players can share one copy. There is no reason to download another copy every time you click or one for each player.

The IFrame player API was really designed to make it easy use javascript to load one player on the page with minimal coding and to ease setting of options. Since you are using 9 players there is really no reason to load 9 copies of the same player_api

There is more about IFrame api here https://developers.google.com/youtube/iframe_api_reference and there are also some YouTube videos on how to use it as well.

I figured it out:
https://jsfiddle.net/hzyrfkwb/185/

This is only loading 1, right?
https://jsfiddle.net/hzyrfkwb/130/

That’s it! Just the one copy of the script.

1 Like

How about this one

Is this only loading 1 copy of the script?

This one is set up differently.

https://jsfiddle.net/hzyrfkwb/296/

const load = (function() {
    "use strict";

    function _load(tag) {
        return function(url) {
            return new Promise(function(resolve, reject) {
                const element = document.createElement(tag);
                const parent = "body";
                const attr = "src";
                element.onload = function() {
                    resolve(url);
                };
                element[attr] = url;
                document[parent].appendChild(element);
            });
        };
    }
    return {
        js: _load("script")
    };
}());
(function manageCover() {
    "use strict";
    const hide = (el) => el.classList.add("hide");

    function coverClickHandler(evt) {
        const cover = evt.currentTarget;
        hide(cover);
    }
    const cover = document.querySelector(".jacketc");
    cover.addEventListener("click", coverClickHandler);
}());
const videoPlayera = (function makeVideoPlayer() {
    "use strict";

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

    function onPlayerStateChange(event) {
        const player = event.target;
        const playerVars = player.b.b.playerVars;
        if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
            player.seekTo(playerVars.start);
        }
    }

    function addVideo(video) {
        const videoId = video.getAttribute("data-id");
        new YT.Player(video, {
            width: 606,
            height: 344,
            videoId: videoId,
            playerVars: {
                autoplay: 1,
                controls: 1,
                showinfo: 1,
                rel: 0,
                iv_load_policy: 3,
                cc_load_policy: 0,
                fs: 0,
                disablekb: 1,
                loop: true,
                start: 1,
                end: 204
            },
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        });
    }

    function init(opts) {
        addVideo(opts.video, opts.playerVars || {});
    }
    return {
        init
    };
}());
(function iife() {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function initPlayer(wrapper) {
        videoPlayera.init({
            video: wrapper.querySelector(".video")
        });
    }

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        if (!window.YT) {
            load.js("https://www.youtube.com/player_api").then(function() {
                YT.ready(function() {
                    initPlayer(wrapper);
                });
            });
        } else {
            initPlayer(wrapper);
        }
    }
    const cover = document.querySelector(".jacketc");
    cover.addEventListener("click", coverClickHandler);
}());
const videoPlayer = (function makeVideoPlayer() {
    "use strict";
    const players = [];

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

    function onPlayerStateChange(event) {
        const player = event.target;
        if (event.data === YT.PlayerState.PLAYING) {
            const otherVideos = (video) => video !== player;
            const pauseVideo = (video) => video.pauseVideo();
            players.filter(otherVideos).forEach(pauseVideo);
        }
        const playerVars = player.b.b.playerVars;
        if (playerVars.loop && event.data === YT.PlayerState.ENDED) {
            player.seekTo(playerVars.start);
        }
    }

    function addVideo(video, desiredPlayerVars) {
        const videoId = video.getAttribute("data-id");
        const defaultPlayerVars = {
            autoplay: 1,
            controls: 1,
            showinfo: 1,
            rel: 0,
            iv_load_policy: 3,
            cc_load_policy: 0,
            fs: 0,
            disablekb: 1
        };
        const playerVars = Object.assign(defaultPlayerVars, desiredPlayerVars);
        players.push(new YT.Player(video, {
            width: 200,
            height: 200,
            videoId: videoId,
            playerVars,
            events: {
                "onReady": onPlayerReady,
                "onStateChange": onPlayerStateChange
            }
        }));
    }

    function init(opts) {
        addVideo(opts.video, opts.playerVars || {});
    }
    return {
        init
    };
}());

function loadPlayer(containerSelector, playerVars) {
    "use strict";
    const show = (el) => el.classList.remove("hide");

    function initPlayer(wrapper) {
        videoPlayer.init({
            video: wrapper.querySelector(".video"),
            playerVars
        });
    }

    function coverClickHandler(evt) {
        const wrapper = evt.currentTarget.nextElementSibling;
        show(wrapper);
        if (!window.YT) {
            load.js("https://www.youtube.com/player_api").then(function() {
                YT.ready(function() {
                    initPlayer(wrapper);
                });
            });
        } else {
            initPlayer(wrapper);
        }
    }
    const cover = document.querySelector(containerSelector);
    cover.addEventListener("click", coverClickHandler);
}
loadPlayer(".playa", {
    start: 900,
    end: 1200
});
loadPlayer(".playb", {
    start: 30,
    end: 50
});
loadPlayer(".playc", {
    start: 30,
    end: 50
});
loadPlayer(".playd", {
    start: 30,
    end: 50
});
loadPlayer(".playe", {
    start: 30,
    end: 50
});
loadPlayer(".playf", {
    start: 30,
    end: 50
});
loadPlayer(".playg", {
    start: 30,
    end: 50
});
loadPlayer(".playh", {
    start: 30,
    end: 50
});
loadPlayer(".playi", {
    start: 30,
    end: 50
});