0

I have instances of jPlayer (jquery audio player): jPlayer1, jPlayer2, jPlayer3, jPlayer4, each initialized and preloaded with audio files.

Calling function below will traverse an existing array and adding the methods that plays the preloaded audio.

function addPlayAudioMethodToExerciseArray(){
    for (i in qaArray){
        qaArray[i].playAnswer = function(){ $('#jPlayer'+i).jPlayer('play',0);}
    }
}  

It creates the method alright except for the part ('#jPlayer'+i) is not evaluated to become ('#jPlayer1'), ('#jPlayer2'), etc.

Many thanks in advance. Note: I'm a noob.

10davvid
  • 33
  • 4
  • This is an extremely common pitfall for those new to JavaScript. – Pointy Jan 28 '12 at 14:19
  • Can you tell us what contains qaArray ? - in you for(i in qaArray) your i begin to 0, so the first '#jPlayer'+i will be '#jPlayer0'... which does not exists. I also think that you'll have to add some closure or you i will always be the last one (qaArray.length-1 ). – dievardump Jan 28 '12 at 14:21
  • I simplified it for posting. The original code had if (i>0){//start traversing}. So yes the method is added starting with qaArray[1]. It works when '#jsPlayer1' is hard-coded. Of course then all methods just triggers the same jsPlayer1; not as intended. – 10davvid Jan 28 '12 at 14:56

2 Answers2

2

The problem is that all those "playAnswer" functions are wrapped around the very same "i" variable. That is, there's only one "i" (and in this case, since you didn't declare it with var, it's global!).

What you need to do is use another function to provide a separate "i" for each one of the callbacks.

function addPlayAudioMethodToExerciseArray(){
    function makePlayerCallback(i) {
      return function() {
        $('#jPlayer' + i).jPlayer('play', 0);
      };
    }

    for (var i = 0; i < qaArray.length; ++i){
        qaArray[i].playAnswer = makePlayerCallback(i);
    }
}

The "makePlayerCallback" function has its own parameter "i", which, being effectively local to that function, will result in callback functions that have their own "i" individually. Each call to that function creates what's called a "closure" around the returned callback function. (Note that my loop starts at zero; if your identifiers in the HTML start at 1, you'll need to account for that by adding 1 somewhere. Thanks to @DieVarDump for that note.)

Note that I declared the "i" used in the loop with var to make it local to "addPlayAudioMethodToExerciseArray" (boy that's a long function name; I hope you won't have to type it too often :-). Also, I used it as a numeric index, under the assumption that"qaArray" is really an honest-to-gosh array, and not just n object. It's good practice to use numeric indexing for arrays.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 1
    And if the IDs really start from 1 (jPlayer1, jPlayer2, jPlayer3, jPlayer4) you'll have to call makePlayerCallback(i+1); because array indexe starts from 0 – dievardump Jan 28 '12 at 14:33
  • console.debug still shows: playAnswer: function () {$('#jPlayer' + i).jPlayer('play', 0);} – 10davvid Jan 28 '12 at 14:40
  • That's OK, @10davvid - it's a different "i" because of the additional function call (to `makePlayerCallback()`). – Pointy Jan 28 '12 at 15:47
  • Sorry, spoke too soon. YES, IT WORKS! So that's OK then, the Id gets evaluated at runtime (when the method is invoked). Thanks all. @Pointy you taught me function can return function. Cool. – 10davvid Jan 28 '12 at 20:52
  • Wew. now the code is working flawlessly, I still can't understand it. If console.debug shows: playAnswer: function () {$('#jPlayer' + i).jPlayer('play', 0);} meaning i needs its value when method playAnswer is invoked, but by then there is no i values wrapping it anymore ???? Seems like magic to me. Anyone can explain it to a six+40-yr-old? – 10davvid Jan 28 '12 at 21:11
0

use colsures

try this :

    for(i in qaArray)
    {
        qaArray[i].playAnswer = function (num)
        {
            return function ()
            {
                $('#jPlayer' + num).jPlayer('play', 0);
            } ;
        }(i)
    };
Royi Namir
  • 144,742
  • 138
  • 468
  • 792