I have two Google Sheets add-ons that I have written for private use by users in my domain. Both add-ons use the onOpen function to generate a menu in Sheets. Both are written with the standard format provided in the Google Developers documentation. An example of the code for the menu is below. Note that no triggers are installed in any portion of my script.
function onOpen(e) {
var ui = SpreadsheetApp.getUi();
ui.createAddonMenu()
.addItem('1️⃣ Authorize', 'authFunction')
.addItem('2️⃣ Format Sheet', 'ResetDataHTML')
.addSubMenu(ui.createMenu('3️⃣ Type & Clean Up')
.addItem('🅰️ Set Trip type', 'setTripType')
.addItem('🅱️ Remove & Set Count', 'deleteNoTrans'))
.addItem('4️⃣ 📧 Email to Transportation', 'emailSheetNote')
.addToUi();
return;
}
The add-ons both function properly. The "problem" I am noticing is when viewing the Execution Logs in the new IDE. For one add-on the onOpen function is constantly running/completing at an interval of about 1-3 seconds. The other add-on seems to run the onOpen function at intervals of about 20-30 minutes. My question is, "why would these add-ons continue to run the onOpen function? Am I noticing normal behavior or is this abnormal? (I have not noticed this behavior with any other script that uses the onOpen function.)
Thank you to anyone that might have some insight as to my issue.
Yes. Every time you or the other users visit or refresh the sheet, it does trigger the onOpen trigger thus possibly showing in your execution logs multiple times. Don't worry about it as that is entirely normal.
Related
For months I'm trying, without success, to submit my Google Sheets Add-On to be available at Google Workspace Marketplace. On the last tentatives I'm receiving this message:
The App doesn’t meet the publishing review criteria on the following:
Menu - Menu options not shown after App is installed. Please ensure that the add-on correctly uses onInstall() and onOpen() to populate its menu. The menu items populate when the add-on is first installed and when a different file is opened. See Editor add-on authorization.
My question is: How can I simulate the installation by myself in order to detect what function or variable is causing the problem?
I already try to avoid declaring Global variables, tried zillions of different ways to populate the menu, but it seems that nothing work. The documentation of Google Apps Script is too generic, the people at GWM doesn't show what error is happening. I really doesn't know what can I do.
How can I avoid a situation that I cannot replicate?
If I just have access to the my own add on GWM page to test it.
Sometimes I ask myself if Google is interested in have third party add on. It's so hard to have information.
Any help will be welcomed.
This is my initialization routine right now:
var ui = function(){
return SpreadsheetApp.getUi()}
/**
* #OnlyCurrentDoc
* ver: https://developers.google.com/apps-script/guides/services/authorization
*/
// The onOpen function is executed automatically every time a Spreadsheet is loaded
function onOpen(e) {
ui().createAddonMenu()
.addItem('Importar fontes', 'ExtrairComentarios')
.addSeparator()
.addItem('Relação de fatores', 'doFactors')
.addItem('Análise simples', 'doTable')
.addItem('Georreferenciamento', 'doMap')
.addSeparator()
.addItem('Gera matriz multimodal', 'GeraMatrizMM')
.addItem('Análise multimodal', 'doMultimodal')
.addItem('Gráfico multimodal', 'doGet')
.addItem('Gráfico multifatorial', 'doMultifatorial')
.addSeparator()
.addItem('Tutorial', 'openTutorial')
.addSeparator()
.addItem('Versão atual', 'DoVersaoAtual')
.addItem('Start!', 'DoStart')
.addToUi();
// Script external request
//eval(UrlFetchApp.fetch("https://cdnjs.cloudflare.com/ajax/libs/alasql/0.6.2/alasql.min.js").getContentText())
}
/**
* The event handler triggered when installing the add-on.
* #param {Event} e The onInstall event.
*/
function onInstall(e) {
onOpen(e);
}
P.S. Believed me, I already spend months trying to solve this.
Google recently released a way to test Editor add-ons and updated the docs. See https://developers.google.com/apps-script/add-ons/how-tos/testing-editor-addons
Now it's possible to create a test deployment for Editor add-ons. Please checkout the details on the previous link.
If you have a Google Workspace account, an alternative might be to publish the add-on for internal use only for testing purposes. Once you have it working you might make a copy to publish publicly, and keep the internal use only for testing future changes.
To prevent having problems use the simple onOpen trigger only to show the custom menu. If you want that the add-on does something else on open, do that using an installable trigger, this imply to add a way for the end-user to create this trigger, i.e. include a option on the custom menu for that.
I've been struggling for two days now to allow the users from my organization to edit the protected pieces of a spreadsheet using only the script I made.
I've been through hell and how I made it work in the end is, I made a fake hidden sheet where the data is stored, and then onOpen, I copy-paste that data to the sheet that the user sees (that they cannot edit). I want to make the UX a bit better if possible, and I was hoping there is a way to force the onOpen trigger from the script. I know I probably didn't do this right, but I cannot spend more time researching, so I need to brute-force it now. (I've tried onChange triggers, I've tried setting permissions in my web app, using doPost, and my brain hurts, this is the first time I'm doing scripting).
TL;DR
Is there a way to refresh the whole tab from the script editor? I need to trigger the onOpen event without the user having to reload the page.
To "force" the onOpen simple trigger you have the following options
call onOpen
function respondToChange(e){
onOpen();
}
If your onOpen function requires the event object you will have to emulate it.
function respondToChange(e){
const event = {};
// add the required properties to event
onOpen(event);
}
change the spreadsheet locale by using setSpreadsheetLocale
Related
How to change Google Apps Script locale?
When a function is run by clicking a button or choosing a custom menu item, or through a simple trigger such as onOpen(e) or onEdit(e), it runs under the account of the user at the keyboard.
To trigger a function to run under another account that has rights to the protected ranges, you need an installable trigger.
I created a Google Script for work (that I don't want to share here) and that works perfectly fine with one onOpen() trigger.
Since I was working on that script on a personal Spreadsheet for testing purposes, I eventually moved it to the real Google Sheet it was meant to run on from the beginning and while the onOpen() function still works properly by being called via "Run function" or even "Debug function", the trigger is not fired, and I'm not getting any log or debug info that could potentially help me.
I deleted and recreated the trigger several times as I saw that this was a known work-around for the issue, but it's not changing anything. When I then go check "Current triggers", I see that it hasn't fired even once and I'm clueless as to what's causing this issue...
While not wanting to give away the whole script since it works anyway, I'm providing the code for my triggered function, even though it didn't change since it last worked successfully on my test spreadsheet:
function onOpen()
{
var aSheet = SpreadsheetApp.getActiveSheet();
var emailRow = 2;
var emailColumn = 3;
for(; !aSheet.getRange(emailRow, emailColumn).isBlank(); emailRow++)
{
aSheet.getRange(emailRow, 19).setValue(matchNPandCIO(emailColumn, emailRow));
}
}
The only thing I can add and that's probably not related is that the spreadsheet on which I now have the script trying to run had an ownership change today and that I'm now its owner. I'm running out of ideas and things to try...
And yes, I also made sure that I gave the script the required authorizations it needs (done after creating the trigger).
Simple triggers like onOpen run anonymously so if matchNPandCIO calls methods that require authorization to run it will fail.
The alternative is to use an installable trigger.
Related
Google Doc onOpen will not fire when spreadsheet is accessed
I have been using a Google Sheet with an attached Apps Script.
I have written the code myself and the code adds a custom menu as well as shows a Sidebar with various 'buttons'.
Until recently (few weeks ago) everything used to work fine.
But now suddenly the Sidebar no longer shows up unless I go, click on the option in the custom menu.
How do I get it working again please?
In the OnOpen function within the script I call the following:
function onOpen() {
// Code to create custom menu goes here
showSideBarUserInterface();
}
function showSideBarUserInterface() {
var html =
HtmlService.createTemplateFromFile('SideBarUserInterface').evaluate()
.setWidth(UI_SIDEBAR_WIDTH)
.setTitle("What would you like to do?")
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
var ss = SpreadsheetApp.getActive();
SpreadsheetApp.getUi().showSidebar(html);
}
I had a similar problem recently and I finally went into the script editor edit menu and current project triggers and created an onOpen() trigger and that does the trick for me. I didn't think that I had to do that with simple triggers but recently I add some additional functionality and so maybe that required authorization which maybe is why I need the installable version. I don't really know the reason. But it works.
I have now removed the call to showSideBarUserInterface() from the onOpen function and instead created a trigger to call showSideBarUserInterface function directly when the spreadsheet is opened - rather than having a trigger which calls the onOpen function again.
In my view having a trigger which calls the onOpen function explicitly is a bad programming example - since it is supposed to be called automatically - but that is my view.
I do see that the onOpen function does run automatically when I open the spreadsheet so with the 'On spreadsheet open' trigger to run showSideBarUserInterface function everything seems to work as I want it to.
I have a script that is creating a copy of a form. When the form is opened by the user for the first time I'd like it to display the sidebar or menus items. Is this possible before any authentication flow has occurred?
Adding an onOpen function the doesn't seemed to have worked as it's not automatically triggered unless you've already been through the authentication process.
The way add-ons work seems to be the behaviour I'd like but I'm unsure if you can create Add-ons for Forms yet.
Code samples would help please... Thanks
It is possible to create menu items for a Form via onOpen() prior to the user authorizing. For example, the following will create a single menu with a single menu item:
function onOpen(e) {
// Only creates menu item, and nothing else
FormApp.getUi()
.createMenu('My Menu')
.addItem('My Menu item','myFunction')
.addToUi();
}
function myFunction() {
// Functionality here; may include code that requires authorization
}
The thing to keep in mind is that onOpen should only be used to create the menus -- it should not contain any code that requires authorization. The reason is that Apps Script allows onOpen() to run without authorization, but will prevent its execution entirely if anything inside of it requires authorization. This is a user-safety mechanism -- onOpen() is run before the user interacts with the Form, and it should never automatically run things without getting the user's permission first. Therefore, if a script hasn't been authorized, Apps Script will only allow certain tasks (like menu creation) to be performed.
For the same reason, it is important not to use global variables which access Apps Script services. Global variables are read and processed as the script file is read, and thus execute before the user can be asked to authorize. If you use global variables, it's best practice to limit them to simple constants.
You can read more about the Apps Script Authorization Lifecycle. This documentation focuses on the authorization of Apps Script add-ons, but much of it is relevant to regular Apps Script scripts.
The other answer is correct about authorizations, the onOpen has limited functionalities because it runs without user explicit permission. You can use it to create a sidebar as well (not only menu items)
example below :
function onOpen() {
var userInterface = createUi();
var ui = formApp.getUi();
ui.showSidebar(userInterface)
}
function createUi(){
var app = UiApp.createApplication().setTitle('test sidebar');
var panel = app.createVerticalPanel();
panel.add(app.createLabel('This is a SideBar'));
return app.add(panel);
}
As mentioned above too (but I insist ;-) be careful if you use global service calls as these are executed when EVERY function is called (including the onOpen) and might prevent your script from working as expected.