Josh
Josh

Reputation: 285

Dynamically Updating a Variable in JS

My page has multiple videos on it and I'm trying to enable seeking through the YouTube API on all of them. These videos are generated dynamically, so I can't pre-define them all at once, unfortunately. If I could, the following would work:

<script>
function onYouTubePlayerAPIReady() {
      player = new YT.Player('ytplayer1', {
      });
      player2 = new YT.Player('ytplayer3', {
      });
      player3 = new YT.Player('ytplayer3', {
      });
      etc. etc.
}
function onPlayerReady(event) {
    event.target.playVideo();
}
function seek(sec){
    if(player){
        seconds += sec;
        player.seekTo(seconds, true);
    }
}

</script>

But because each page will have a different number of dynamically generated videos, I'm running into an issue.

I can make the first and last videos work using the following code:

#Initial javascript + first video
<script>
function onYouTubePlayerAPIReady() {
      player = new YT.Player('ytplayer1', {
      });
}
function onPlayerReady(event) {
    event.target.playVideo();
}
function seek(sec){
    if(player){
        seconds += sec;
        player.seekTo(seconds, true);
    }
}
var old_foo = onYouTubePlayerAPIReady;
</script>

<iframe id="ytplayer1" width="789" height="444" src="https://www.youtube.com/embed/p4vLPmVAwlo?enablejsapi=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<button type="button" onclick="player.seekTo(60)">60s</button>
<button type="button" onclick="player.seekTo(120)">120s</button>



#Second video plus the JS to go with it
<iframe id="ytplayer2" width="789" height="444" src="https://www.youtube.com/embed/_9ahu4c5zdI?enablejsapi=1" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<button type="button" onclick="player2.seekTo(60)">60s</button>
<button type="button" onclick="player2.seekTo(120)">120s</button>


<script>
function onYouTubePlayerAPIReady() {
  old_foo();
  player2 = new YT.Player('ytplayer2', {
  });
}

</script>

But whenever I try to add another, the middle ones stop working. It seems like my final call of the onYouTubePlayerAPIReady function is overwriting everything before it, without executing the function at each step. I've tried updating my old_foo var, the onYouTubePlayerAPIReady function, defining a new var, etc. None of it seems to work! But I also suck at javascript so I'm sure I'm just missing something simple.

Help?

Upvotes: 3

Views: 102

Answers (2)

J&#243;zef Podlecki
J&#243;zef Podlecki

Reputation: 11293

Here's how you can add yt players dynamically with seekTo buttons

let players = [];
const button = document.querySelector("#button");
const newId = (() => {
  const prefix = "player";
  let id = 1;
  return () => {
    let newId = id;
    id = id + 1;

    return {
      id: newId,
      cssId: `${prefix}${newId}`
    }
  }
})()

const createButton = (text, clickEvent) => {
  const element = document.createElement("button");
  element.textContent = text;
  element.setAttribute("type", "button");
  element.addEventListener("click", clickEvent);
  return element;
}

const seekPlayer = (id, value) => {
  const player = players.find(pl => pl.id === id);
  player.seekTo(value);
}

const createPlayer = () => {
  const parent = document.body;
  const container = document.createElement("div");
  const playerPlaceholder = document.createElement("div");
  const result = newId();
  playerPlaceholder.setAttribute("id", result.cssId);

  const button1 = createButton('60s', () => seekPlayer(result.id, 60));
  const button2 = createButton('120s',() => seekPlayer(result.id, 120));
  container.appendChild(playerPlaceholder);
  container.appendChild(button1);
  container.appendChild(button2);

  parent.appendChild(container);

  const player = new YT.Player(result.cssId, {
    height: '100',
    width: '100',
    videoId: 'M7lc1UVf-VE',
    events: {
      'onReady': (event) => {

        players = [...players, {
          id: result.id,
          player: event.target
        }]
      },
    }
  });
}

button.addEventListener("click", () => {
  createPlayer();
})
<script src="https://www.youtube.com/iframe_api"></script>
<button id="button">Add player</button>

Upvotes: 0

Ed Lucas
Ed Lucas

Reputation: 7345

The onYouTubePlayerAPIReady() function is called automatically when the player API code has loaded, so you only need to define it once. Inside of that, you should be able to define your multiple players. Your JS could be condensed into the following:

<script>
    function onYouTubePlayerAPIReady() {
      player = new YT.Player('ytplayer1', {
      });
      player2 = new YT.Player('ytplayer2', {
      });
    }
</script>

Working CodePen using onYouTubeIframeAPIReady instead of onYouTubePlayerAPIReady: https://codepen.io/edlucas/pen/wvKVVaP

Also see: https://developers.google.com/youtube/iframe_api_reference

EDIT

If you need to create the markup on the fly and still want to load them all when the API is ready, one way is to queue the videos up in an array that's used when onYouTubePlayerAPIReady is called.

var videos = ['ytplayer1', 'ytplayer2'];
var players = [];

function onYouTubeIframeAPIReady() {
    videos.forEach((video, i) =>
        players[i] = new YT.Player(video, {
            events: {
                'onReady': onPlayerReady,
            }
        });
   };
}

You can then use your favorite method to add videos to the array, (e.g. videos.push('ytplayer3')) as long as you do it before the API is added to the page, or at least before it's ready.

Upvotes: 2

Related Questions