1

I'm working with a user script that creates a menu of clickable links for the user. These entries are stored into an array initially and then the array is iterated over and the functions are added to the .click callback.

This is how the menu is built up:

registerMenuCommand('Options', function() { DisplaySlideMenu(true); });

function registerMenuCommand( oText, oFunc ) {
    falsifiedMenuCom[falsifiedMenuCom.length] = [oText,oFunc];
}

I can successfully add and execute the menu commands using standard javascript and code like the following:

for( var i = 0; GM_falsifiedMenuCom[i]; i++) {
    var menuEntry;
    mdiv.appendChild(menuEntry = document.createElement('a'));
    menuEntry.setAttribute('href','#');
    menuEntry.onclick = new Function('falsifiedMenuCom['+i+'][1](arguments[0]); var e = arguments[0]; e.stopPropagation(); return false;');
        menuEntry.appendChild(document.createTextNode(falsifiedMenuCom[i][0]));
}

but I decided to try and convert it to jQuery (so that things looked a little prettier) which I made look like this:

for( var i = 0; falsifiedMenuCom[i]; i++) {
    var mEntry = $('<a href="#">' + falsifiedMenuCom[i][0] + '</a>');
    mEntry.click(function () { debugger; falsifiedMenuCom[i][1](arguments[0]); var e = arguments[0]; e.stopPropagation(); return false; });
    mdiv.append(mEntry);
}

And of course it doesn't work. Everything gets added correctly to the menu, but when I click on one of the entries the .click gets called and I get an error Uncaught TypeError: Cannot call method '1' of undefined. This makes sense because the .click function for all the menus is falsifiedMenuCom[i]1 and i == falsifiedMenuCom.length which is past the end of the array. I understand why all that is, but is there anyway to get the .click function to actually take the actual array value of falsifiedMenuCom[i][1] and NOT just attempt to call falsifiedMenuCom[i][1] itself? Should i just be sticking with the plain old javascript?

Austin Brunkhorst
  • 20,704
  • 6
  • 47
  • 61
Mordred
  • 3,734
  • 3
  • 36
  • 55
  • 1
    Seems like `i` is trouble due to the new closure. Try with jQuery's `$.each` instead a `for` loop, that way you can use `i` wherever inside the new scope. Plus your `for` loop seems weird, where's the length being checked? – elclanrs Feb 05 '13 at 02:33
  • Similiar http://stackoverflow.com/questions/14698872/ajax-send-request-to-php-same-value/14698890 – Musa Feb 05 '13 at 02:33
  • Thanks, all it took was using `$.each`. I borrowed the original function and never realized the length wasn't being checked in the `for` loop, but it doesn't need to because `falsifiedMenuCom[i]` will be NULL when `i >= falsifiedMenuCom.length`. – Mordred Feb 05 '13 at 02:56
  • @elclanrs: The test is for the truthyness of `falsifiedMenuCom[i]`. It's apparently an array of arrays, so all indices will be truthy until `i` goes out of bounds. – the system Feb 05 '13 at 02:57
  • 1
    @Mordred: To be clear, the issue is that JavaScript doesn't have block scope. All non-global variables are scoped to the nearest enclosing function. Because of this, you need a function invocation in each iteration of the loop in order to scope a new `i` variable to each handler function. The callback passed to `.each()` creates this required variable scope when it's invoked per iteration. – the system Feb 05 '13 at 02:59

0 Answers0