0

Question: how to access shortcut or action or other local variables

Related: Similar questions but not success:

Java Solution: set final modifier to variables that required in anonymous function

Target Source code:

//plugin.buttons is collection of button objects
for (var i in plugin.buttons) {
    var button = plugin.buttons[i];
    var icon = button.icon;
    var text = button.text;
    var shortcut = button.shortcut;
    var action = button.action; //action is a function ( or method )

    if (shortcut != null && shortcut.length > 0) {
        if ($.isFunction(action)) {
            console.log(shortcut); //it's valid shortcut
            //using jQuery hotkey plugin
            $('div[contenteditable]').bind('keydown', shortcut, function () {
                console.log(shortcut); //it's undefined
                action.call(); //it's undefined also
                return false;
            });
        }
    }
}
Community
  • 1
  • 1
Behnam
  • 2,212
  • 2
  • 22
  • 32
  • it should just work as shown since JS can reach those vars via closure... EDIT: whoops, wrap your for loop in a function, the oldest major workaround for lack of loop scope in the book. – dandavis Jul 01 '14 at 21:26

1 Answers1

3

You can pass it in as event data

for (var i in plugin.buttons) {
    var button = plugin.buttons[i];
    var icon = button.icon;
    var text = button.text;
    var shortcut = button.shortcut;
    var action = button.action; //action is a function ( or method )

    if (shortcut != null && shortcut.length > 0) {
        if ($.isFunction(action)) {

            $('div[contenteditable]').on('keydown', {shortcut : shortcut}, function (e) {

                console.log(e.data.shortcut);

            });
        }
    }
}

But in this case the real issue is that there is no special scope in a for loop, so defining variables inside the for loop just overwrites the same variables on each iteration, which is why it doesn't work when the event handler is called at a later time.

You have to lock in the variable in a new scope

for (var key in plugin.buttons) {
    (function(i) {
        var button = plugin.buttons[i];
        var icon = button.icon;
        var text = button.text;
        var shortcut = button.shortcut;
        var action = button.action; //action is a function ( or method )

        if (shortcut != null && shortcut.length > 0) {
            if ($.isFunction(action)) {
                console.log(shortcut); //it's valid shortcut
                //using jQuery hotkey plugin
                $('div[contenteditable]').bind('keydown', shortcut, function () {
                    console.log(shortcut); //it's undefined
                    action.call(); //it's undefined also
                    return false;
                });
            }
        }
    })(key);
}
adeneo
  • 312,895
  • 29
  • 395
  • 388
  • 1
    what about the for-loop non-scope thingy ? – dandavis Jul 01 '14 at 21:28
  • @dandavis - Oh, you're right, there's no scope in a for loop, so the variables are overwritten on each iteration. Passing them as event data would solve that, but an IIFE would be more approriate, changing this answer now. – adeneo Jul 01 '14 at 21:29
  • your first answer doesn't work for me because second parameter must be a string to work with jQuery Hotkey. But your second answer is nice solution and worked well! thanks. – Behnam Jul 01 '14 at 21:40