YouTube API Event Handler Stops Working Without Error Messages

I’ve been working on this problem for hours and can’t figure out what’s going wrong. I’m trying to create multiple YouTube video players that work with click events, but some of them just stop responding.

The Issue:
My code works perfectly for the first two video links, but links 3 and 4 throw an error: Uncaught TypeError: videoInstance.loadVideoById is not a function. The weird part is that the exact same function works fine for the first two links.

It seems like the YouTube player objects only get created properly for the first two videos. Why would this happen?

What I’m Trying to Do:
I want users to click on text links and have YouTube videos play in a modal popup. Each video should start and stop at specific times that I define in an array.

My Current Code:

// Global variables
var videoPlayers = [];
var isCurrentlyPlaying = false;

videoConfig = [{
    buttonID: "btn0",
    containerID: "video1",
    videoID: "dQw4w9WgXcQ",
    startTime: 15,
    endTime: 25
}, {
    buttonID: "btn1",
    containerID: "video2",
    videoID: "oHg5SJYRHA0",
    startTime: 5,
    endTime: 15
}, {
    buttonID: "btn2",
    containerID: "video3",
    videoID: "kJQP7kiw5Fk",
    startTime: 45,
    endTime: 55
}, {
    buttonID: "btn3",
    containerID: "video4",
    videoID: "9bZkp7q19f0",
    startTime: 90,
    endTime: 105
}];

// Called when YouTube API is ready
function onYouTubePlayerAPIReady() {
    console.log("Total videos to setup: " + videoConfig.length);
    
    for(j = 0; j < videoConfig.length; j++) {
        console.log("Setting up video #" + j);
        
        var clickButton = document.getElementById(videoConfig[j].buttonID);
        console.log("Button ID: " + clickButton.id);
        
        var currentConfig = videoConfig[j];
        console.log("Current video config:");
        console.log(currentConfig);
        
        clickButton.addEventListener("click", function() {
            selectedID = $(this).attr("id").replace("btn", "");
            
            console.log("Clicked video #" + (parseInt(selectedID) + 1));
            
            var videoCode = videoConfig[selectedID].videoID;
            var startPos = videoConfig[selectedID].startTime;
            var endPos = videoConfig[selectedID].endTime;
            
            var videoInstance = new YT.Player(videoConfig[selectedID].containerID);
            
            console.log("Video ID: " + videoCode);
            console.log("Start: " + startPos + ", End: " + endPos);
            
            $("#videoModal").css({"display": "block"});
            $("#videoModal").animate({"opacity": "0.8"}, 800, function() {
                
                console.log("Showing video player");
                $(".video-container").show();
                
                console.log("Player object:");
                console.log(videoInstance);
                
                videoInstance.loadVideoById({
                    'videoId': videoCode, 
                    'startSeconds': startPos, 
                    'endSeconds': endPos
                });
            });
            
            // Monitor player state
            setTimeout(function() {
                var checkCount = 0;
                stateChecker = setInterval(function() {
                    
                    var currentState = videoInstance.getPlayerState();
                    var stateDescription;
                    
                    switch(currentState) {
                        case -1: stateDescription = "not started"; videoInstance.playVideo(); break;
                        case 0: stateDescription = "finished"; break;
                        case 1: stateDescription = "playing"; break;
                        case 2: stateDescription = "paused"; break;
                        case 3: stateDescription = "loading"; break;
                        case 5: stateDescription = "ready"; break;
                        default: stateDescription = "unknown state";
                    }
                    
                    console.log(currentState + ": " + stateDescription);
                    
                    if(currentState == 1) {
                        isCurrentlyPlaying = true;
                    }
                    
                    // Close modal when video ends
                    if((isCurrentlyPlaying) && (currentState == 0)) {
                        setTimeout(function() {
                            console.log("Closing video modal");
                            $(".video-container").css({"display": "none"});
                            $("#videoModal").animate({"opacity": "0"}, 800, function() {
                                $("#videoModal").css({"display": "none"});
                            });
                            isCurrentlyPlaying = false;
                        }, 300);
                        clearInterval(stateChecker);
                    }
                    
                    // Prevent infinite loop
                    checkCount++;
                    if((checkCount > 500) && (currentState != 1) && (currentState != 2) && (currentState != 0)) {
                        clearInterval(stateChecker);
                        console.log("State checker stopped to prevent infinite loop");
                    }
                }, 20);
            }, 900);
        });
    }
}

// Load YouTube API
var scriptTag = document.createElement('script');
scriptTag.src = "//www.youtube.com/player_api";
var firstScript = document.getElementsByTagName('script')[0];
firstScript.parentNode.insertBefore(scriptTag, firstScript);

I’ve been debugging this for days and I’m completely stuck. The same exact code works for some videos but not others. Has anyone seen this kind of behavior with the YouTube API before?

I’ve hit this exact issue before with YouTube API. You’re creating new YT.Player instances inside your event handlers without initializing them first. When you call new YT.Player(videoConfig[selectedID].containerID), the player object isn’t fully ready yet, so loadVideoById fails.

Here’s how I fixed it: pre-create all player instances during the API ready callback and store them in an array. Don’t create new players on each click - initialize everything upfront in onYouTubePlayerAPIReady() and just reference existing instances in your handlers. Use videoPlayers[selectedID].loadVideoById() instead of making new instances.

Also throw in some error handling around player creation in case DOM elements don’t exist yet. YouTube API gets weird about timing with multiple players.