0

So these two work fine:

$(document).on("click", "#_something", function(){
    $('#vid').attr('src',video_config["something"].video);

});
$(document).on("click", "#_anotherthing", function(){
    $('#vid').attr('src',video_config["anotherthing"].video);

});

However, something and nothing are properties of an object I made, so I attempted to do this:

for (var key in video_list){
    $(document).on("click", "#_"+key, function(){
        $('#vid').attr('src',video_list[key].video);
    });
}

Which sort of messed it up, and set all the src values to the last video_list[key].video value I have. To rephrase, this assigned all of the src properties the same value.

How do I do this correctly without manually writing each of the event handlers?

Louis93
  • 3,843
  • 8
  • 48
  • 94

3 Answers3

4

This is because your Handler function captures the key variable which is scoped to the parent function. When your Handler executes, key has the last value.

The fix is to capture the current value at each iteration by using yet another function scope. Like this:

for (var k in video_list) {
  function(key) {
    // create your event handler here using key
  }(k);
}

This is explained in this question that is basically the same as this one: javascript closure in a for loop

In ES6 browsers, let being block scoped you can use it as a shortcut:

for (let k in video_list) {
  let key = k;
  // same code as your question goes here, using key.
}
Community
  • 1
  • 1
jods
  • 4,581
  • 16
  • 20
  • `let` is not supported in most browsers – blgt Mar 28 '14 at 19:48
  • That's why I said _in ES6 browsers_. Also, _most_ browsers depends on your target audience: it's supported by IE11+, at least FF24+ and at least Chrome 30+. For those ES6 compatibility things you can look at Kangax compatibility tables: http://kangax.github.io/es5-compat-table/es6/#let – jods Mar 28 '14 at 19:51
  • What's your browser? IE11 here, your fiddle works perfectly, no error. But the output is 333, so now I know. I'll fix my answer with this experiment, thanks! – jods Mar 28 '14 at 20:06
  • It didn't work with FF 27.0.1 and Chrome 33.0.1750.154 (these are the ones I have installed) – blgt Mar 28 '14 at 20:08
  • 1
    Regarding FF, it's supported since FF 2, which supports Javascript 1.7. The trick is that you have to opt-in JS 1.7 support by using ` – jods Mar 28 '14 at 20:11
  • That's a neat trick. It worked in FF, but still not in chrome. – blgt Mar 28 '14 at 20:14
  • Not 100% sure about Chrome but I guess it's still enabled by an experimental switch in chrome://flags. That's a pity because you can't assume your users enable experimental switches :( – jods Mar 28 '14 at 20:16
2

Here's a simple way using one event handler, a class and a data attribute:

$(document).on("click", ".video", function(){
    var key = $(this).data("key"); // in the element add data-key="xyz"
    $('#vid').attr('src',video_list[key].video);
});
Wilmer
  • 2,511
  • 1
  • 14
  • 8
1

The quick and dirty hack:

for (var key in video_list){
    (function(key){// create a new context, so not all handlers point the the same key
        $(document).on("click", "#_"+key, function(){
            $('#vidSrc').attr('src',video_list[key].video);
        });
    })(key);
}

The correct way:

$(document).on("click", ".some-new-class-you-just-defined", function() {
    $(this).attr('src', video_list[$(this).attr('id').slice(1)].video);
});

EDIT: Add substring to the id. It's better to have some sort of lookup mechanism, rather than storing this in id's, as @jods suggested.

blgt
  • 8,135
  • 1
  • 25
  • 28
  • 1
    Your second piece of code is not correct because `id` starts with an additional underscore `_` rather than the raw property name. A bit of fiddling around is required. It's quite hacky, if you go this route you ought to put the property name in an additional attribute, like `data-videokey=something`. – jods Mar 28 '14 at 19:54
  • @jods You are correct. I was focusing on the loop and missed this. – blgt Mar 28 '14 at 20:05