-1

Upon document.ready, I am defining several functions, then attempting to call them using window[variable], where the variable is the name of the function. I came upon this soution here: Calling a JavaScript function named in a variable. Here is my code:

jQuery(document).ready(function() {


function playSlide0(){
    player0.playVideo();
    console.log('slide0 fired');
}
function playSlide1(){
    player1.playVideo();
    console.log('slide1 fired');
}
function playSlide2(){
    player2.playVideo();
    console.log('slide2 fired');
}

swiper.on('slideChangeStart', function () {


    var currentSlide = swiper.activeIndex;
    var currentVid = document.getElementById('video'+currentSlide);
    var currentVidId = 'slide_'+currentSlide;
    var playSlideFunction = 'playSlide'+currentSlide;

    window[playSlideFunction]();

});

});

Instead of calling my function, I am getting the error 'window[playSlideFunction] is not a function'. Any thoughts? Thank you.

  • You've defined the functions in the scope of the anonymous function, they are not defined globally, i.e. they are not properties of `window`. – Teemu Sep 06 '17 at 18:33
  • While this is possible in theory, you should unlearn everything about this immediately. Please add the relevant HTML and we can show you how to write this properly. –  Sep 06 '17 at 18:34
  • Possible duplicate of [Javascript - Variable in function name, possible?](https://stackoverflow.com/questions/3733580/javascript-variable-in-function-name-possible) – Jamie T Sep 06 '17 at 18:41

3 Answers3

1

Inside document.ready the value of this is not the window, but the document

jQuery(document).ready(function() {
  console.log(document === this); // true
  console.log(window === this); // false
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Which is why window[playSlideFunction] is undefined.
The proper way to handle this, would be with an object you control, and not the document or window

jQuery(document).ready(function() {
  var funcs = {
    playSlide0: function() {
      player0.playVideo();
      console.log('slide0 fired');
    },
    playSlide1: function() {
      player1.playVideo();
      console.log('slide1 fired');
    },
    playSlide2: function() {
      player2.playVideo();
      console.log('slide2 fired');
    }
  }

  swiper.on('slideChangeStart', function() {
    var currentSlide = swiper.activeIndex;
    var currentVid = document.getElementById('video' + currentSlide);
    var currentVidId = 'slide_' + currentSlide;
    var playSlideFunction = 'playSlide' + currentSlide;

    funcs[playSlideFunction]();
  });
});
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • What has this to do with `this`? – Teemu Sep 06 '17 at 18:35
  • @Teemu - If you define a function inside `document.ready` it's not attached to `window`, but `document`, and can't be called with `window[function_name]` – adeneo Sep 06 '17 at 18:36
  • ?? They are defined in the scope of that anonymous function, that's why they are not properties of `window`. – Teemu Sep 06 '17 at 18:37
  • When something is defined inside `document.ready` it's not ***global***, and can't be accessed on the window, and that is the problem the OP is having, and thus the answer to the question. – adeneo Sep 06 '17 at 18:41
  • Yes, _I_ know that, but I can't see how `this` is involved in the case, since we're talking about scopes ..? And functions defined in `document.ready`'s argument are not assigned to the `document`, assigning variables as properties is a feature of the globally declared variables/functions only. Not my downvote, though. – Teemu Sep 06 '17 at 18:43
  • It's involved because if `this` was the global object, i.e. `window`, the functions would be available on the `window`. I'm just using `this` in the topmost example to show that the context isn't global inside `document.ready`. And yes, the only context where functions are added to `this` is in the global scope – adeneo Sep 06 '17 at 18:46
  • Now, had we known what the `player0.playVideo()` function does, and where `player0` comes from, there would be a much more elegant solution to this -> https://jsfiddle.net/449y749t/1/ – adeneo Sep 06 '17 at 18:49
0

You could wrap the function in an object

var fn = {
    playSlide0: function () {
        player0.playVideo();
        console.log('slide0 fired');
    },
    playSlide1: function () {
        player1.playVideo();
        console.log('slide1 fired');
    },
    playSlide2: function () {
        player2.playVideo();
        console.log('slide2 fired');
    }
}

and call it with the name

fn['playSlide' + currentSlide]();
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Generally speaking, this is not a good way to go about this. It's hard to give a really specific answer because we don't have the rest of your page, but in general you are better off with a single function that takes a parameter telling it which thing to operate on. This is basic principle called DRY - Do Not Repeat Yourself.

You might do something like this:

Say you have a bunch of video elements - you can grab them all with:

var players = document.querySelectorAll('video');

Now players is a list of players -- you can reference each player in order with:

players[0] //etc

Now you only need one function regardless of how many players you have:

function playSlide(index){
  players[index].playVideo();
  console.log('player ' + index  + 'fired');
}

And you can use it with something like this:

var currentSlide = swiper.activeIndex
playSlide(currentSlide)

Now if you add more players, you don't need to change your code and if you want to change something in the code, you only need to change it in one place.

Mark
  • 90,562
  • 7
  • 108
  • 148