Youtube iframe Api and Angularjs route
Asked Answered
W

3

6

I encountered a problem with Youtube Iframe Api used with angularjs.

I think the problem is the call of "onYouTubeIframeAPIReady" function.

I use angularjs with routes and the function doesn't fire when the route is changed, however when I hit F5 it's ok the player is loaded.

Is there a way to make angularjs with routes and youtube API work?

I didn't manage to add more file in the code but "pageX.htm" looks like this :

<button ng-click="video()">Create</button>
<div youtube-player id="test-playerX" ></div>

And there is the code for "index.htm"

<!DOCTYPE html>
<html ng-app="sc">
  <body>

    Homepage - <a href="#page1">Page1</a> - <a href="#page2">Page2</a>

    <div ng-view></div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
    <script src="https://code.angularjs.org/1.4.3/angular-route.min.js"></script>
    
    <script>
      var sc = angular.module('sc', ['ngRoute']);

      sc.config(['$routeProvider', function($routeProvider) {
        $routeProvider
          .when('/page1', {
            templateUrl: 'page1.htm'
          })
          .when('/page2', {
            templateUrl: 'page2.htm'
          })
      }]);

            // Run
      sc.run(['$rootScope', function($rootScope) {

                var tag = document.createElement('script');

                // This is a protocol-relative URL as described here:
                //     http://paulirish.com/2010/the-protocol-relative-url/
                // If you're testing a local page accessed via a file:/// URL, please set tag.src to
                //     "https://www.youtube.com/iframe_api" instead.
                tag.src = "http://www.youtube.com/iframe_api";
                var firstScriptTag = document.getElementsByTagName('script')[0];
                firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
            }]);


      sc.service('youtubePlayerApi', ['$window', '$rootScope', '$log', function ($window, $rootScope, $log) {
        var service = $rootScope.$new(true);

        // Youtube callback when API is ready
        $window.onYouTubeIframeAPIReady = function () {
            $log.info('Youtube API is ready');
            service.ready = true;
            service.createPlayer();
        };

        service.ready = false;
        service.playerId = null;
        service.player = null;
        service.videoId = "sGPrx9bjgC8";
        service.playerHeight = '390';
        service.playerWidth = '640';

        service.bindVideoPlayer = function (elementId) {
            $log.info('Binding to player ' + elementId);
            service.playerId = elementId;
        };

        service.createPlayer = function () {
            $log.info('Creating a new Youtube player for DOM id ' + this.playerId + ' and video ' + this.videoId);
            return new YT.Player(this.playerId, {
                height: this.playerHeight,
                width: this.playerWidth,
                videoId: this.videoId
            });
        };

        service.loadPlayer = function () {
            // API ready?
            if (this.ready && this.playerId && this.videoId) {
                if(this.player) {
                    this.player.destroy();
                }

                this.player = this.createPlayer();
            }
        };

        return service;
      }]);

      sc.directive('youtubePlayer', ['youtubePlayerApi', function (youtubePlayerApi) {
          return {
              restrict:'A',
              link:function (scope, element) {
                  youtubePlayerApi.bindVideoPlayer(element[0].id);
              }
          };
      }]);
      
      sc.controller('replaycontroller', function ($scope,youtubePlayerApi) {
              $scope.video = function () {
                youtubePlayerApi.createPlayer();
                console.log("test");
              }

          });
    </script>


  </body>
</html>

Any help is appreciated :)

[EDIT] : I have updated the code to test the fonction createPlayer and confirm that the player is working when changing pages

Whisenhunt answered 5/8, 2015 at 9:30 Comment(0)
W
3

As Karan Kapoor says in the last comment, the best way to use youtube api with angularjs is to use github.com/brandly/angular-youtube-embed

Whisenhunt answered 2/9, 2015 at 15:56 Comment(0)
W
2

OK I have found a solution, it is far not the cleanest but it works.

I admit that in the controller when you are changing routes, the youtube api is already initialized. So the controller just create the player.

When F5 or first time loading requested, we must fire onYouTubeIframeAPIReady to instantiate the player.

Here is the code :

<!DOCTYPE html>
<html ng-app="sc">
  <body>

    Homepage - <a href="#page1">Page1</a> - <a href="#page2">Page2</a>

    <div ng-view></div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
    <script src="https://code.angularjs.org/1.4.3/angular-route.min.js"></script>
    
    <script>
      var sc = angular.module('sc', ['ngRoute']);

      sc.config(['$routeProvider', function($routeProvider) {
        $routeProvider
          .when('/page1', {
            templateUrl: 'page1.htm',
            controller: 'replaycontroller'
          })
          .when('/page2', {
            templateUrl: 'page2.htm'
          })
      }]);

            // Run
      sc.run(['$rootScope', function($rootScope) {
               var tag = document.createElement('script');

                // This is a protocol-relative URL as described here:
                //     http://paulirish.com/2010/the-protocol-relative-url/
                // If you're testing a local page accessed via a file:/// URL, please set tag.src to
                //     "https://www.youtube.com/iframe_api" instead.
                tag.src = "http://www.youtube.com/iframe_api";
                var firstScriptTag = document.getElementsByTagName('script')[0];
                firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
               
            }]);


      sc.service('youtubePlayerApi', ['$window', '$rootScope', '$log', function ($window, $rootScope, $log) {
        var service = $rootScope.$new(true);

        // Youtube callback when API is ready
        $window.onYouTubeIframeAPIReady = function () {
            $log.info('Youtube API is ready');
            service.ready = true;
            service.createPlayer();
        };

        service.ready = false;
        service.playerId = null;
        service.player = null;
        service.videoId = "sGPrx9bjgC8";
        service.playerHeight = '390';
        service.playerWidth = '640';

        service.getStatus = function () {
          return service.ready;
        };

        service.bindVideoPlayer = function (elementId) {
            $log.info('Binding to player ' + elementId);
            service.playerId = elementId;
        };

        service.createPlayer = function () {
            $log.info('Creating a new Youtube player for DOM id ' + this.playerId + ' and video ' + this.videoId);
            return new YT.Player(this.playerId, {
                height: this.playerHeight,
                width: this.playerWidth,
                videoId: this.videoId
            });
        };

        service.loadPlayer = function () {
            // API ready?
            if (this.ready && this.playerId && this.videoId) {
                if(this.player) {
                    this.player.destroy();
                }

                this.player = this.createPlayer();
            }
        };

        return service;
      }]);

      sc.directive('youtubePlayer', ['youtubePlayerApi', function (youtubePlayerApi) {
          return {
              restrict:'A',
              link:function (scope, element) {
                  youtubePlayerApi.bindVideoPlayer(element[0].id);
              }
          };
      }]);

      sc.controller('replaycontroller', function ($scope,youtubePlayerApi) {
        if (youtubePlayerApi.getStatus() == true) {
          youtubePlayerApi.bindVideoPlayer("test-player1");
          youtubePlayerApi.createPlayer();
        }
      });

        
    </script>


  </body>
</html>
Whisenhunt answered 5/8, 2015 at 11:9 Comment(4)
How did you use it finally? How can I use it with multiple youtube videos on the same page? So basically I'll have all the youtube video ID's in an array, and I would like to initialize them on the page as videos in an ng-repeat and then capture events on each one of them individually. Any idea how that can be done?Peripheral
Hello finally I no longer use youtube api but youtube iframe tag... It's really not easy to implement youtube api on an angularjs app. Sorry I didn't helpWhisenhunt
Found the best way to do it. If you wanna implement it yourself, use Google's iFrame API. or use the angular repo github.com/brandly/angular-youtube-embed . I used the latter. :)Peripheral
Thanks to you I will try it as soon as I canWhisenhunt
H
0

I had the same problem and what i did was to reset the script to null and then set it again:

init() {
    if (window["YT"]) {
        window["YT"] = null;
        this.tag = document.createElement("script");
        this.tag.src = "https://www.youtube.com/iframe_api";
        this.firstScriptTag = document.getElementsByTagName("script")[0];
        this.firstScriptTag.parentNode.insertBefore(this.tag, this.firstScriptTag);
    }
    this.tag = document.createElement("script");
    this.tag.src = "https://www.youtube.com/iframe_api";
    this.firstScriptTag = document.getElementsByTagName("script")[0];
    this.firstScriptTag.parentNode.insertBefore(this.tag, this.firstScriptTag);
    window["onYouTubeIframeAPIReady"] = () => this.startVideo();
}
Horseshoe answered 18/9, 2020 at 0:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.