Определение того, какой элемент был нажат в пользовательском меню

Я создал пользовательское меню с несколькими элементами, однако у меня возникли трудности с определением того, какой элемент щелкнул пользователь. Я хочу использовать одну и ту же функцию для каждого элемента в этом меню, но я не могу понять, как передать информацию о том, какой элемент был нажат в мою функцию. Несколько идей, которые у меня были, но я не смог реализовать: попытка передать параметр при нажатии кнопки (параметр может быть именем кнопки или ее индексом) или попытка каким-то образом определить, какой элемент был нажат по индексу (т.е. "элемент 3 был нажат") и передать эту информацию функции.

var ui = SpreadsheetApp.getUi(); //shortcut to access ui methods
var ps = PropertiesService.getScriptProperties(); //shortcut to access properties methods
var ss = SpreadsheetApp.getActiveSpreadsheet() //shortcut to access spreadsheet methods

function onOpen() {
  var menu = ui.createMenu('Scripts') //create a menu with this name
  var subMenu = ui.createMenu('Timestamps')
        for (var n = 0; n < ss.getNumSheets(); n++){
          var sheets = ss.getSheets();
          var sheetName = sheets[n].getName();
          Logger.log(sheetName)
          subMenu.addItem(sheetName, 'sheets')
        }
      menu.addSubMenu(subMenu).addToUi(); //add it to the UI
}

function sheets(sheet){
  var response = ui.alert(sheet, 'Add to timestamps?', ui.ButtonSet.YES_NO_CANCEL) //create a button and store the user value in response
  if(response == ui.Button.YES){ //if the user pressed YES (add this item to timestamp list)
    if(sheets.indexOf(sheet) != -1){ //check if item is already in the array. If it is, do nothing
      //item is aleady in array
    }else if(sheets.indexOf(sheet) == -1){ //check if it is NOT in the array. If it isn't, add it
      //item isn't in array, but needs to be added
      sheets.push(sheet) //add the item to the array
    }
  }else if(response == ui.Button.NO){ //if the user pressed NO (remove item from the list)
    if(sheets.indexOf(sheet) != -1){ //if the item already exists but needs to be removed)
      //item exists in array, but needs to be removed
      var index = sheets.indexOf(sheet); //find where the item is stored
      sheets.splice(index, 1); //splice that item out of the array
    }else if(sheets.indexOf(sheet) == -1){ //if the item already doesn't exist in the array, do nothing
      //item already isn't in array
    }
  }
  ps.setProperty('updatedSheets', JSON.stringify(sheets)) //storing the new value of sheets so that we can view it in the properties screen (only for debugging purposes)
}

В настоящее время этот код делает следующее: когда электронная таблица открыта, создается меню с именем Scripts с подменю внутри него с именем Timestamps. Внутри временных меток подменю у меня есть один элемент для каждого листа. Цель состоит в том, что когда пользователь нажимает на один из элементов, появляется всплывающее окно с 3 кнопками: Да, Нет и Отмена. Если они нажмут Да, этот элемент должен быть добавлен в листы массива. Если они нажмут «Нет», этот элемент должен быть удален. Если они нажмут Отмена, ничего не произойдет. У меня пока работает добавление и удаление элементов, если они указывают в коде конкретный лист, но как мне его получить, чтобы я мог использовать одну и ту же функцию для каждого элемента и передавать лист параметров (в зависимости от того, какой элемент был щелкнул) в функциональные листы.

Пример функциональности кода, если я жестко запрограммирую имя листа без передачи параметра в функцию:

function sheets(){
  var response = ui.alert('Sheet1', 'Add to timestamps?', ui.ButtonSet.YES_NO_CANCEL) //create a button and store the user value in response
  if(response == ui.Button.YES){ //if the user pressed YES (add this item to timestamp list)
    if(sheets.indexOf('Sheet1') != -1){ //check if item is already in the array. If it is, do nothing
      //item is aleady in array
    }else if(sheets.indexOf('Sheet1') == -1){ //check if it is NOT in the array. If it isn't, add it
      //item isn't in array, but needs to be added
      sheets.push('Sheet1') //add the item to the array
    }
  }else if(response == ui.Button.NO){ //if the user pressed NO (remove item from the list)
    if(sheets.indexOf('Sheet1') != -1){ //if the item already exists but needs to be removed)
      //item exists in array, but needs to be removed
      var index = sheets.indexOf('Sheet1'); //find where the item is stored
      sheets.splice(index, 1); //splice that item out of the array
    }else if(sheets.indexOf('Sheet1') == -1){ //if the item already doesn't exist in the array, do nothing
      //item already isn't in array
    }
  }
  ps.setProperty('updatedSheets', JSON.stringify(sheets)) //storing the new value of sheets so that we can view it in the properties screen (only for debugging purposes)
}



Ответы (1)


Я знаю, что eval зло, но я не могу не использовать его. Да если делать кучу функций динамически через eval то остальное тривиально.

var FUNC_STR = 'sheets';  //the real function name (global constant)

function onOpen() {
  //...
  for(var n = 0; n < ss.getNumSheets(); n++){
    var sheets = ss.getSheets();
    var sheetName = sheets[n].getName();
    subMenu.addItem(sheetName, FUNC_STR + n);  //note here
  }
  menu.addSubMenu(subMenu).addToUi();
}


//dynamically make functions
var evalString = '';
for(var n = 0; n < ss.getNumSheets(); n++) {
  evalString += 'function ' + FUNC_STR + n + '() { ' + 
    FUNC_STR + '(' + n + ') }';
}
eval(evalString);


//now you can take a argument.
//function name should be the same as FUNC_STR.
function sheets(sheet) {
  SpreadsheetApp.getUi().alert(sheet);
  //...
}
person Sangbok Lee    schedule 27.06.2018
comment
Решение подразумевает, что вы вызываете одну и ту же функцию, но с разных листов, и вы можете передать информацию which sheet с помощью своего трюка, верно? В таком случае я полагаю, что это лучше, чем ничего :) - person Giampaolo Ferradini; 11.08.2020