I am trying to create a dynamically populated menu in Google Sheets using Google Apps Script.
The sheet is called 'Classes'. The values in the classes sheet are 8H, 9p1, 9p2 etc. They are in cells A1:A12. In the debugger the array, menuItemArray, loads correctly with all expected classes from the 'Classes' sheet.
The error I get is:
TypeError: Cannot find function addSubMenu in object 9p1. (line 13, file "Code")
This is when stepping into the line
menuItemArrayClass = menuItemArray [menuCount]
I would be really grateful for any help as to what I am doing wrong or any better ways to do it.
Here is my code:
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
var menuCount = 0;
ui.createMenu('Manage Timetable')
.addItem('First item', 'menuItem1')
.addSeparator()
var menuItemArray = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Classes').getDataRange().getValues();
for (menuCount=1;menuCount < menuItemArray.length;++menuCount) {
var menuItemArrayClass = []
menuItemArrayClass = menuItemArray [menuCount]
.addSubMenu(ui.createMenu('Manage Classes')
.addItem(menuItemArrayClass [menuCount] + 'Schedule Timetable', 'runBatch1'))
.addToUi();
}
}
myFunction()
for several functions in the custom menu.I understand like above. If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Unfortunately, in the current stage, when a function is added to the custom menu with addItem
method, the argument cannot been able to be used. And when one of functions in the custom menu is run, the information about the function name which was run cannot be retrieved. By this, your goal cannot be directly achieved. So it is required to use the workaround.
When I saw your question, for your goal, I thought that this thread is useful. At google.script.run, it is required to be able to directly run the function at the script editor and the function is included in this
. But at the custom menu, when the function is included in this
, the function can be run even when the function cannot be directly run at the script editor. When the function is run in only GAS side, the function can be run even when the function cannot be directly run with the script editor. I thought that this situation can be used for the workaround.
When your script is modified by including this workaround, it becomes as follows. Please copy and paste it to the container-bound script of Spreadsheet which has the headers ("Col1", "Col2",,,) at the 1st row and the values from 2nd row. And when you run the script, please open the Spreadsheet. By this, the custom menu is added. And when new column is added by copying, the additional column is also added to the custom menu. And when the function at the custom menu is run, the values corresponding to the column are activated.
function onOpen(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var headers = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Custom Menu')
.addItem('First item', 'menuItem1')
.addSeparator();
var subMenu = ui.createMenu('Sub-menu');
for (var i = 0; i < headers.length; i++) {
var dynamicMenu = headers[i];
subMenu.addItem(dynamicMenu,'dynamicItem');
}
menu.addSubMenu(subMenu).addToUi();
}
function onEdit(e) {
onOpen(e);
}
function menuItem1() {
SpreadsheetApp.getUi()
.alert('You clicked the first menu item!');
}
function dynamicItem() {
SpreadsheetApp.getUi()
.alert('You clicked the dynamic menu item!');
}
function installFunctions() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var headers = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Custom Menu')
.addItem('First item', 'menuItem1')
.addSeparator();
var subMenu = ui.createMenu('Sub-menu');
for (var i = 0; i < headers.length; i++) {
var dynamicMenu = headers[i];
this[dynamicMenu] = dynamicItem(i); // Added
subMenu.addItem(dynamicMenu,dynamicMenu); // Modified
}
menu.addSubMenu(subMenu).addToUi();
}
function dynamicItem(i) { // Added
return function() {
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(2, i + 1, sheet.getLastRow() - 1, 1).activate();
}
}
installFunctions(); // Added
function onOpen() {} // Modified: This can be used as the simple trigger.
function onEdit() {} // Modified: This can be used as the simple trigger.
function onChange() {} // Added: Please install OnChange event trigger to this function.
onChange()
. By this, when the column is deleted, the custom menu is updated.function onEdit() {}
and function onChange() {}
are used for running onOpen();
.onOpen();
.onOpen
is run every time. So when the number of columns are large, the process cost will be high. So please be careful this.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With