Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading Youtube Iframe API with RequireJS

I'm trying to use the Youtube Iframe API inside a module definded with Require JS. As this API is loaded async and calls a function once is loaded, I used a requireJS plugin called "async", that worked before with google maps api.

However, this time something isn't working. My module starts this way: define(['text!fmwk/widgets/video/video.html','fmwk/utils/browser','async!http://www.youtube.com/iframe_api'], function (videoTpl,root) { ... });

and chrome console fires this error: Uncaught Error: Load timeout for modules: async!http://www.youtube.com/iframe_api_unnormalized3,async!http://www.youtube.com/iframe_api http://requirejs.org/docs/errors.html#timeout

If I don't use async plugin the object YT or its functions are undefinded, and the same happens if I download the API code. The API is loaded sometimes if I put an script tag in the head tag of the html file. All this is expected, but I don't understand because async plugin fails.

Thank you for your attention and help :)

like image 455
dgnin Avatar asked Oct 11 '12 15:10

dgnin


2 Answers

I'm not familiar with the async requireJS plugin, but here's some sample code (taken from YouTube Direct Lite) that loads the iframe API asynchronously from within a requireJS module named player. It's using jQuery to do the actual library loading, though.

define(['jquery'], function($) {
  var player = {
    playVideo: function(container, videoId) {
      if (typeof(YT) == 'undefined' || typeof(YT.Player) == 'undefined') {
        window.onYouTubeIframeAPIReady = function() {
          player.loadPlayer(container, videoId);
        };

        $.getScript('//www.youtube.com/iframe_api');
      } else {
        player.loadPlayer(container, videoId);
      }
    },

    loadPlayer: function(container, videoId) {
      new YT.Player(container, {
        videoId: videoId,
        width: 356,
        height: 200,
        // For a list of all parameters, see:
        // https://developers.google.com/youtube/player_parameters
        playerVars: {
          autoplay: 1,
          controls: 0,
          modestbranding: 1,
          rel: 0,
          showinfo: 0
        }
      });
    }
  };

  return player;
});
like image 66
Jeff Posnick Avatar answered Sep 19 '22 15:09

Jeff Posnick


After some research and being unstatisfied with the other answers, I have solved this for this exact case plus possible others without the extra fluff, by extending the require async! plugin to support a named callback which then makes sure the module code is only executed once the API is fully loaded.

The core problem seems to be, that YouTube Iframe API does not allow you to configure the callback's name, but dictates it to be "onYouTubeIframeAPIReady" which our small upgrade to the async plugin solves. This solution still uses the global window.YT, but works without jQuery.

require(
    ['async!//www.youtube.com/iframe_api!undefined:onYouTubeIframeAPIReady'],
    function() { 

        // this codes executes your code once YouTube Iframe API is loaded and ready
        player = new YT.Player({ ... });

    }
);

Also works with inline require calls:

define([], function () {
    // .. some of your other code here

    require(['async!//www.youtube.com/iframe_api!undefined:onYouTubeIframeAPIReady'],      function () {

        // this codes executes your code once YouTube Iframe API is loaded and ready
        player = new YT.Player({ ... });

    });
});

The code is in my opinion much more clean than any seen before. Also, the performance improvements by loading the API in the very last moment were massive, especially when used with dozens of players. The API will of course only be loaded once and cached as usual.

Upgraded !async plugin: https://github.com/mhrisse/requirejs-plugins/blob/master/src/async.js

Pull request for upgraded !async plugin: https://github.com/millermedeiros/requirejs-plugins/pull/39

The upgrade should be fully backward compatible, that's why there is this rather ugly undefined as the first plugin parameter. Any ideas how to make this more beautiful and simple are very welcome.

like image 28
xexe Avatar answered Sep 21 '22 15:09

xexe