1

So I'm trying to put in additional buttons into my tinyMCE wysiwyg editor on wordpress. They're showing up and are functioning (sort of). When clicked they're just outputting the last variable in the array, which is weird because I am using the variable in other places in the loop and it works fine.

(function() {
  tinymce.create('tinymce.plugins.col', {
    init : function(ed, url) {
      var col_id = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven'];
      for(var i = 0; i < col_id.length; i++){
        var colNum = col_id[i];
        ed.addButton(colNum+'_col', {
          title : colNum+' Column',
          image : url+'/images/mce/'+colNum+'.png',
          onclick : function() {
            ed.selection.setContent('['+colNum+'_col]' + ed.selection.getContent() + '[/'+colNum+'_col]');
           }
         }); // ***** Col *****
         ed.addButton(colNum+'_col_first', {
           title : colNum+' Column First',
           image : url+'/images/mce/'+colNum+'.png',
           onclick : function() {
             ed.selection.setContent('['+colNum+'_col_first]' + ed.selection.getContent() + '[/'+colNum+'_col_first]');
            }
          });  // ******  Col First ******
          ed.addButton(colNum+'_col_last', {
            title : colNum+' Column Last',
            image : url+'/images/mce/'+colNum+'.png',
            onclick : function() {
              ed.selection.setContent('['+colNum+'_col_last]' + ed.selection.getContent() + '[/'+colNum+'_col_last]');
            }
          });   //*********  Col Last **********
        }
      },
      createControl : function(n, cm) {
        return null;
      },
    });
    tinymce.PluginManager.add('col', tinymce.plugins.col);
  })();

What happens when I click one of the buttons is it output the short code of [eleven_col][/eleven_col], which confuses me because the Title and image url is output correctly.

MikO
  • 18,243
  • 12
  • 77
  • 109
user1888521
  • 135
  • 1
  • 11

2 Answers2

3

I think this is the classic closure problem, which can hopefully be explained here: JavaScript closure inside loops – simple practical example

Wrap everything inside of your for loop in this:

(function (colNum) {
    // Your code in the for loop
})(col_id[i]);

And remove your var colNum = col_id[i]; line

So the final code will look like this:

(function() {
    tinymce.create('tinymce.plugins.col', {
        init : function(ed, url) {
            var col_id = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven'];
            for(var i = 0; i < col_id.length; i++){
                (function (colNum) {    // <---------------------- ADDED THIS
                    ed.addButton(colNum+'_col', {
                        title : colNum+' Column',
                        image : url+'/images/mce/'+colNum+'.png',
                        onclick : function() {
                            ed.selection.setContent('['+colNum+'_col]' + ed.selection.getContent() + '[/'+colNum+'_col]');

                        }
                    }); // ***** Col *****

                    ed.addButton(colNum+'_col_first', {
                        title : colNum+' Column First',
                        image : url+'/images/mce/'+colNum+'.png',
                        onclick : function() {
                            ed.selection.setContent('['+colNum+'_col_first]' + ed.selection.getContent() + '[/'+colNum+'_col_first]');

                        }
                    });  // ******  Col First ******

                    ed.addButton(colNum+'_col_last', {
                        title : colNum+' Column Last',
                        image : url+'/images/mce/'+colNum+'.png',
                        onclick : function() {
                            ed.selection.setContent('['+colNum+'_col_last]' + ed.selection.getContent() + '[/'+colNum+'_col_last]');

                        }
                    });   //*********  Col Last **********
                })(col_id[i]);    // <------------------------- ADDED THIS
            }
        },
        createControl : function(n, cm) {
            return null;
        }
    });
    tinymce.PluginManager.add('col', tinymce.plugins.col);
})();
Community
  • 1
  • 1
Ian
  • 50,146
  • 13
  • 101
  • 111
3

@Ian has the answer correct, but you might like to organise the code this way, with a named function instead of an IIFE inside the loop.

The col_id parameter to the function is actually unnecessary, as the function has visibility of the col_id variable, but I think it's a bit clearer this way.

(function () {
    tinymce.create('tinymce.plugins.col', {
        init: function (ed, url) {
            function handleColumn(col_id, i) {
                // loop code in here
            }

            var col_id = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven'];
            for (var i = 0; i < col_id.length; i++) {
                handleColumn(col_id, i);
            }
        },
        createControl: function (n, cm) {
            return null;
        },
    });
    tinymce.PluginManager.add('col', tinymce.plugins.col);
})();
Paul Grime
  • 14,970
  • 4
  • 36
  • 58