Skip to content Skip to sidebar Skip to footer

Why Do All Of The Keybindings In This Directive Get Overwritten By The Last One?

I'm attempting to create a directive that binds specific keypresses to functions specified in the scope of a controller, but all of the callback functions seem to be overridden by

Solution 1:

You've fallen for a common trap: variables in JavaScript are always function scoped. When you do this:

for (var k in attribute) {
    console.log('binding ' + k + ' as ' + attribute[k]);
    Mousetrap.bind(k, function() { return attribute[k](scope, element); });
}

With that bind(), you're creating four closures that all close over the variable k—but they all close over the same variable. You don't get a new one for each run of the loop. The console.log works perfectly because the value of k is used immediately. The closure doesn't evaluate k until it's actually run, and by then, its value has changed to whatever it was when the loop finished.

Depending on your target audience, the easiest way by far to fix this is to use let instead of var. let does block scoping (which works about how you'd expect), but is a fairly recent invention, and I'm not sure how well it's supported.

Otherwise, to get a new scope, you need a new function:

for (var k in attribute) {
    (function(k) {
        console.log('binding ' + k + ' as ' + attribute[k]);
        Mousetrap.bind(k, function() { return attribute[k](scope, element); });
    })(k);
}

This passes the outer k to the function's inner k, which will be a different variable every time. You could also split this out into a little factory function, but for something this tiny, I wouldn't bother.

Post a Comment for "Why Do All Of The Keybindings In This Directive Get Overwritten By The Last One?"