user1232145
user1232145

Reputation:

create a javascript function programmatically

Need this for the youtube api // the onStateChange callback functions!

I want to programmatically create functions which will listen to the "onStateChange" event emitted by several youtube player. Adding the listener works already:

function onYouTubePlayerReady(playerId) {
  var ytpStateManager = playerId +"_StateManager";
  document.getElementById(playerId).addEventListener("onStateChange", ytpStateManager );
...

The function I need to create based on the playerId variable ("ytp_1", "ytp_2", ...) is

function ytpStateManager(newState) {
  ytpStateHelper(playerId , newState);
}

So the result for the playerId "ytp_1" would look like this:

function ytp_1_StateManager(newState) {
  ytpStateHelper("ytp_1", newState);
}

Works also but right now I need to add them manually for each player, which is not what I need. I want to create them automatically when a new player sends a readyState event.

My problem is that it seems like these functions need to be a global functions to work properly. I tried several options for days now. My problem is that I do not know how (if there is a way) to define a global function, incl. the function name, programmatically, based on another variable.

Its a bummer that the ytp does not emit an event which includes the state AND the player/target. Would make things much easier. All this is basically the workaround as I need all to do stuff on all stateChanges.

If there is a better/simpler way, PLEASE let me know :) Otherwise a solution for this question is highly welcome.

Maybe there is a way to rerout the event, to make it more "accessible"?

I read in the spec that .addEventListener also takes a object, so I tried to bind the event to a dedicated object. But again, it did not get triggered. Feels like I tested everything ...

UPDATE I am now switching to the iframe player (from swfobject) because that one provides an event which includes playerId and state :D Yeahhh!! After spending week with the wrong ytplayer this feels like a great advancement. Also seems like yt wants us to use the iframe player which can dynamically use html5 when supported.

Upvotes: 6

Views: 5112

Answers (4)

Anton Baksheiev
Anton Baksheiev

Reputation: 2251

1)You can create Function object new Function([params], "BODY") So you can combine body of your function as string variable and put into as BODY

Example: var twoNumAverage = new Function("x", "y", "return (x + y)/2") console.log(twoNumAverage(3,7))

2)And new can create dynamically name and BODY

Example

var globalObject ={};
var nameFn ='MyNewFunction';

var createFn  = function(object,functionName, Body){
   object[functionName]= new Function(Body); 
}

createFn(globalObject,nameFn,"return (arguments[0] + arguments[1])/2");

You can call your new function:

globalObject[nameFn](10,20);

Result: 15

Please note that in body your function you can get params via collection arguments

Upvotes: 3

nyteshade
nyteshade

Reputation: 2872

Here's a way to create a named proxy function that executes another function with the context you supply.

function createNamedProxy(name, fn, context) { 
  var template = [
          '(function @name() {',
          '  @name.fn.apply(@name.context || window, arguments);',
          '})'
      ].join('').replace(/@name/g, name),

  result = eval(template);
  result.fn = fn;
  result.context = context;

  return result;
}  

// Example Usage
var anonymous = function() { alert( document === this ); },
    named = createNamedProxy('Named', anonymous, document);

// Will alert 'true'
named();

The solution above creates a function that can create and return a named function that executed whatever you'd like. If you don't supply context, it will assume the window object just like a normal anonymous function would. To create the solution you wanted you would do:

var varName = 'ytp_1';
window[varName + '_StateManager'] = 
    createNamedProxy(varName + '_StateManager', function(newState) {
      ytpStateHelper(varName, newState);
    });

Where varName could be any programmatic prefix you'd like. When invoking ytp_1_StateManager() you would pass in your newState value and the code would call ytpStateHelper with your variable name and the newState.

Hope this helps.

Upvotes: 1

bfavaretto
bfavaretto

Reputation: 71939

You create a function that returns a function:

function createStateManager(playerId) {
    return function (newState) {
        ytpStateHelper(playerId , newState);
    }
}

Then you call your function factory when setting up the event listener:

var player = document.getElementById(playerId);
player.addEventListener("onStateChange", createStateManager(playerId));

DEBUGGING

I'm not sure why that's not working, but here is a debugging suggestion. I suspect you may not be getting the playerId on your onYouTubePlayerReady handler.

function onYouTubePlayerReady(playerId) {
    console.log('Player ready. The player id is: ' + playerId);
    var ytpStateManager = playerId +"_StateManager";
    var player = document.getElementById(playerId);
    player.addEventListener("onStateChange", createStateManager(playerId));
}

function createStateManager(playerId) {
    return function (newState) {
        console.log('State changed for player ' + playerId + '. New state is ' + newState);
        ytpStateHelper(playerId , newState);
    }
}

Could you try that, and post what you get from both console.log calls?

Upvotes: 5

epascarello
epascarello

Reputation: 207527

window["foo"+"bar"] = function(){ console.log("foobar is called"); }

Upvotes: 0

Related Questions