Search code examples
javascriptgoogle-sheetsgoogle-apps-scripttriggers

'For' loop only works once in Apps Script for Google Spreadsheets


So I was in IT class and we were making custom menus for Google sheets, I got curious and I wanted to make some sort of loop of menus. Something with this structure: Menu -> Submenu 1 -> Submenu 2 -> Submenu 3 -> ... and so on.

I thought the best option was to make a 'for' loop, but I have tried so much and it does not work. After trying things the closest thing I have is a code that surprisingly (for me) has a loop but only creates one submenu (Menu -> Submenu 1). The number of repetitions I set in the loop doesnt matter. What is the problem?? Thanks beforehand and sorry for bad english or stupid question (I'm a beginner).

function onOpen(){
  var sheet = SpreadsheetApp;
  var menu = sheet.getUi().createMenu('Menu'); // create a menu
  var parentMenu = menu; // keep a reference to the parent menu
  var subMenu;
  for(i=1 ; i<=5 ; i++){
    subMenu = sheet.getUi().createMenu('Submenu ' + i).addItem('Filling', 'function');
    parentMenu.addSubMenu(subMenu); // add the subMenu to the parentMenu
    parentMenu = subMenu; // update the parentMenu for the next iteration
  }
  menu.addToUi(); // apply everything
}

Solution

  • Modification points:

    • In your script, parentMenu = menu is run for the first time. And, subMenu is sheet.getUi().createMenu('Submenu ' + i).addItem('Filling', 'function'). And, at the first loop, after parentMenu.addSubMenu(subMenu) is run, parentMenu = subMenu is run. By this, parentMenu is changed to subMenu. So, menu has only sheet.getUi().createMenu('Submenu ' + i).addItem('Filling', 'function') of the first loop. And, at menu.addToUi(), the custom menu is added. By this flow, only "Submenu 1" is shown in the custom menu. I guessed that this might be the reason for your current issue.

    Although I'm not sure about function of addItem('Filling', 'function') from your question, in this case, as a simple modification, please test the following modifications.

    Modified script 1:

    function onOpen() {
      var sheet = SpreadsheetApp;
      var menu = sheet.getUi().createMenu('Menu'); // create a menu
      var parentMenu = menu; // keep a reference to the parent menu
      var subMenu;
      for (i = 1; i <= 5; i++) {
        subMenu = sheet.getUi().createMenu('Submenu ' + i).addItem('Filling', 'function');
        parentMenu.addSubMenu(subMenu); // add the subMenu to the parentMenu
        // Remove this line. parentMenu = subMenu; // update the parentMenu for the next iteration
      }
      menu.addToUi(); // apply everything
    }
    

    By this, the following result is obtained.

    enter image description here

    Modified script 2:

    As a simple script, how about the following modification? The same result with the above script is obtained.

    function onOpen() {
      var sheet = SpreadsheetApp;
      var menu = sheet.getUi().createMenu('Menu');
      for (var i = 1; i <= 5; i++) {
        var subMenu = sheet.getUi().createMenu('Submenu ' + i).addItem('Filling', 'function');
        menu.addSubMenu(subMenu);
      }
      menu.addToUi();
    }
    

    Modified script 3:

    I'm worried that I might misunderstand your expected result. So, as another modification, if you want the deep-nested submenus, please test the following sample script.

    function onOpen() {
      const ui = SpreadsheetApp.getUi();
      let subMenu;
      for (var i = 5; i >= 1; i--) {
        const menu = ui.createMenu(`Submenu ${i}`);
        if (i == 5) {
          subMenu = menu.addItem('Filling', 'function');
        } else {
          subMenu = menu.addSubMenu(subMenu);
        }
      }
      ui.createMenu("menu").addSubMenu(subMenu).addToUi();
    }
    

    When this script is run, the following result is obtained.

    enter image description here