I’m currently trying to use the YouTube API as part of a jQuery plugin and I’ve run into a bit of a problem.
The way the YT api works is that you load the flash player and, when it’s ready it will send a call back to a global function called onYouTubePlayerReady(playerId). You can then use that id combined with getElementById(playerId) to send javascript calls into the flash player (ie, player.playVideo();).
You can attach an event listener to the player with player.addEventListener('onStateChange', 'playerState'); which will send any state changes to another global function (in this case playerState).
The problem is I’m not sure how to associate a state change with a specific player. My jQuery plugin can happily attach more than one video to a selector and attach events to each one, but the moment a state actually changes I lose track of which player it happened in.
I’m hoping some example code may make things a little clearer. The below code should work fine in any html file.
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'> <html> <head> <meta http-equiv='Content-Type' content='application/text+html;utf-8'/> <title>Sandbox</title> <link type='text/css' href='http://jqueryui.com/latest/themes/base/ui.all.css' rel='stylesheet' /> <script type='text/javascript' src='http://www.google.com/jsapi'></script> <script type='text/javascript'> google.load('jquery', '1.3.2'); google.load('jqueryui', '1.7.0'); </script> <script type='text/javascript' src='http://swfobject.googlecode.com/svn/tags/rc3/swfobject/src/swfobject.js'></script> <script type='text/javascript'> (function($) { $.fn.simplified = function() { return this.each(function(i) { var params = { allowScriptAccess: 'always' }; var atts = { id: 'ytplayer'+i }; $div = $('<div />').attr('id', 'containerplayer'+i); swfobject.embedSWF('http://www.youtube.com/v/QTQfGd3G6dg&enablejsapi=1&playerapiid=ytplayer'+i, 'containerplayer'+i, '425', '356', '8', null, null, params, atts); $(this).append($div); }); } })(jQuery); function onYouTubePlayerReady(playerId) { var player = $('#'+playerId)[0]; player.addEventListener('onStateChange', 'playerState'); } function playerState(state) { console.log(state); } $(document).ready(function() { $('.secondary').simplified(); }); </script> </head> <body> <div id='container'> <div class='secondary'> </div> <div class='secondary'> </div> <div class='secondary'> </div> <div class='secondary'> </div> </div> </body> </html>
You’ll see the console.log() outputtin information on the state changes, but, like I said, I don’t know how to tell which player it’s associated with.
Anyone have any thoughts on a way around this?
EDIT: Sorry, I should also mentioned that I have tried wrapping the event call in a closure.
function onYouTubePlayerReady(playerId) { var player = $('#'+playerId)[0]; player.addEventListener('onStateChange', function(state) { return playerState(state, playerId, player); } ); } function playerState(state, playerId, player) { console.log(state); console.log(playerId); }
In this situation playerState never gets called. Which is extra frustrating.
Edit:
Apparently calling
addEventListeneron theplayerobject causes the script to be used as a string in an XML property that’s passed to the flash object – this rules out closures and the like, so it’s time for an old-school ugly hack:Tested & working!