Youtube Iframe can't work without refresh

Viewed 957

To reproduce the problem in Stackblitz, click GO to navigate to the component containing iframe, it works now, then go back and forward, the iframe disappears. You have to refresh the page to show the iframe again.

I tried some workaround :

  • I tried to release the object in ngOnDestroy window['onYouTubeIframeAPIReady'] = null; but not success

This is the code how to create iframe

init() {
  var tag = document.createElement('script');
  tag.src = 'https://www.youtube.com/iframe_api';
  var firstScriptTag = document.getElementsByTagName('script')[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}

ngOnInit() {
  this.init();
  window['onYouTubeIframeAPIReady'] = (e) => {
            this.YT = window['YT'];

            this.player = new window['YT'].Player('player', {
              videoId: '1cH2cerUpMQ'
            });
  };
}

TEMPLATE

 <div id="player" >
 </div>

Someone has a workaround with success please share, please.

3 Answers

You can check if youtube api has been already initialized and then just create your player:

player: any;

init() {
  if (window['YT']) {
    this.createPlayer();
    return;
  }

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

  window['onYouTubeIframeAPIReady'] = () => this.createPlayer();
}

ngOnInit() {
  this.init();
}

createPlayer() {
  this.player = new window['YT'].Player('player', {
    videoId: '1cH2cerUpMQ'
  });
}

ngOnDestroy() {
  window['onYouTubeIframeAPIReady'] = null;
  if (this.player) {
    this.player.destroy();
  }
}

Forked Stackblitz

After one week, a workaround that works but it seems "dirty".

In fact, after go back and forward, the function window['onYouTubeIframeAPIReady'] doesn't execute anymore.

So, I put a boolean in this method, reset to false if it's executed. Then, a function check to need to reload after a timeout 3s by considering this value

 //this.needToReload = true in constructor

 ngAfterViewInit(){
    let n = 3;
    var intervalId= setInterval(() => {
            n--;
            this.tick = n*10;
            if (n === 0) {
                clearInterval(intervalId);
                if(this.needToReload)
                {
                  location.reload();
                }
            }
        }, 1000);
  } 

ngOnInit() {
    this.init();
    window['onYouTubeIframeAPIReady'] = (e) => {
        this.YT = window['YT'];
        this.needToReload = false;

        this.player = new window['YT'].Player('player', {
          videoId: '1cH2cerUpMQ'
        });
    };
}

You can destroy and reinit if youtube api has been already;

public player: any;
public YT: any;

init() {
  if (window['YT']) {
    window['YT'] = null;

    if(this.player){
     this.player.destroy();
    }
  this.init();
  }

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

  window['onYouTubeIframeAPIReady'] = () => this.startVideo();
}

ngOnInit() {
  this.init();
}

startVideo() {
  this.player = new window['YT'].Player('player-youtube', {
  videoId: this.linkVideo,
  playerVars: {
    autoplay: 0,
    modestbranding: 1,
    controls: 0,
    disablekb: 1,
    rel: 0,
    showinfo: 0,
    fs: 0,
    playsinline: 1,
    loop: 0,
    origin: window.location.host,
    host: 'https://www.youtube.com'
  },
  events: {
    'onStateChange': this.onPlayerStateChange.bind(this),
    'onReady': this.onPlayerReady.bind(this),
  }
}

ngOnDestroy() {
  window['onYouTubeIframeAPIReady'] = null;
  if (this.player) {
    this.player.destroy();
  }
}

Forked Stackblitz

Related