Google Sheets - Menu Click Function in Library - google-apps-script

I have gsheet menu item as follows, where the executing function resides in library "rm".
ui.createMenu('Test').addItem('Test-Lib', 'rm.test');
I have tested this and it works. However, I was not able to find any documentation on this. So my question is; is this a supported feature which I can rely on going forward?
The use case here is: I will be distributing copies of the same gsheet to different clients, so having a single code repository helps updating all clients at the same time. -

Related

Can one iterate through bound scripts and edit their manifest files via a script?

I am building an application that will have many users, each of whom will have many Google documents. Each doc will have a custom menu and that custom menu will invoke a library script. I may need or want to change the coding in that library script from time to time.
As changes to a library script must be "saved" as a new version in order for the changed version to be passed on to client scripts (in my case, the scripts bound to Google Docs), I need a way that users can "batch" update the version number in their docs' bound script appsscript.json
file.
I have researched this issue and there seems to be two general alternatives: set the client scripts' library mode to "Developmental" or use an add-on.
The problem with the former is that it won't work unless the users are all granted edit mode access to the library script (which seems particularly a bad idea as the users may well not even be known to me).
The problem with the later is essentially complication and cost. If I make the add-on private, it only works for users in the same domain which means I have to create a G-Suite domain (and pay at least (as of this writing) $72 per year per user—a non-starter for this project).
If I make the add-on public, in addition to the complication, I have to sign up to the Google Cloud Platform and the costs for that require one to navigate a veritable maze of choices and alternatives such that at this point, I really have no idea what the cost per service or user would be.
Below I present some "mock-up" code that should at least indicate the direction I am trying to go.
function upDate() {
var version = 23
var scripts = "https://script.google.com/u/0/home"
//while (scripts.hasNext()) {
//var script = files.next();
//Note: All of the script's have the same name as they commence life bound to a template, which template is duplicated to create the rest of the user's docs
if( scriptName = ScriptName){
//set.dependencies.enabledAdvancedServices[].version
}
}
I don't even know if it's possible to step through bound scripts the way one step's through files in a Google Drive, so that is the first question. Then, the second question is whether, assuming you can step through the scripts one by one, you can change a manifest value—in this case, the version number.
One cannot step through container-bound scripts as they are (no longer) located in one's Google Drive. Moreover, despite Google's documentation about using a "stable" value in the version section of the manifest, that documentation appears erroneous. Finally, one cannot programmatically edit standalone scripts.
However, there is a workaround. What I ended up doing was writing a script that steps through all of the involved Google Docs and copies them to a blank template (i.e., in effect, duplicates them all). That blank template has the bound script installed in it with the new version number of the library. Then, delete original docs (via the same script) and voilà, batch update to all of the target docs is accomplished. (One drawback of this is: if Google Doc revision history is important to you, be advised this gambit jettisons that (unless you keep the original versions).

Can a library be used to force all copies of a spreadsheet to reference the most current version of a script?

I've created a Google Sheets spreadsheet template with a script that my users can access via a menu option. This "template" is new and undergoes frequent enhancements and bug fixes.
I'd like to find a way to ensure that all copies that are made of the template access the most recent version of the script.
I read this: https://developers.google.com/apps-script/guides/libraries#testAndDebug
...but the first warning at the top of the page says not to use libraries for long-running scripts. Mine takes 3 - 30 minutes to run, depending upon the amount of input data.
If I do use a library, do I have to put it in development mode in order for copies of the template to reference the latest version of the script?
Sorry. I hope this is making sense. I'd appreciate any advice you might have.

Using Google Apps Script Libraries

I have read all Google documentation on managing and creating libraries, yet I still do not know if they are an appropriate option for the problem I am trying to solve.
I know how to save a version of a standalone script. I know how to add the library to a spreadsheet via the script editor. But I don't understand, very simply, how to trigger the library script within the new spreadsheet.
I have a spreadsheet that serves as an often-copied template within my organization. The template contains a script that (onOpen) accesses data on a separate spreadsheet (a master database) and sets those values on a tab called "admin." The desired result is to have a copy of the master database living within the template sheet (and every subsequent copy of the template sheet). At this point, there are thousands of copies of the template sheet, each running that same script.
Whenever I have to change the script, I have to change it within thousands of sheets. Can I use a library instead? I'd like to be able to create a new version of the script in the library and have all sheets connected to that library experience the change. I understand that the library needs to be in development mode (within each sheet) to do this. I also understand that in order to make this switch, I will probably still have to go into each sheet to add the library. I'm just hoping it will be the last time I have to do such a tedious task.
Any advice or links to solid info is appreciated.
besides making an add-on (already covered in another answer) I will answer your libraries question. They will work for you. What you are missing is the "connect" part.
For this you want to trigger the library code from say, onOpen. The onOpen in the library is not enough and not detected by apps script. Instead each of your spreadsheet's script needs an onOpen(e) which just calls yourlibrary.onOpen(e).
since those "hook" calls rarely change, specially once you stabilize your library api, and using it in "development" mode will let you modify just the library.
whenever one of those hooks needs to change (say a callback from an html GUI needs a new parameter) you need to update all the spreadsheets. to avoid this, make all your callbacks receive a single json object instead of multiple parameters.
Sorry if I am repeating other answers, but I would like to sum up and add something:
You can access your library functions as follows:
From the app using the library you go to the Resources/Libraries. You can see the library name under "Identifier". On the same line where you can select Development mode.
Library name found in resources
Now in your library you have for example a function
function onOpen(e)
{
Browser.msgBox("HELLO!");
}
In the spreadsheet app you wish to access it you use the library name found in the resources, for example "testlibrary"
function onOpen(e)
{
testlibrary.onOpen(e);
}
Now if you have development mode on, the modifications to functions in the library update automatically to your application (spreadsheet) as long as the user using the application has edit access in your library script.
If anyone using your spreadsheet has a restricted access to your library script (meaning only view access) or development selection is off in the application, you have to go to the application's script, Resources/Libraries and select the most recent version of your library to be used in the app everytime you update the library and save a new version of it.
Still, especially if you are using mostly only the onOpen function , I would recommend using the library rather than copy-pasting the function to the script of each spreadsheet, as it is easier to track which scripts are up to date and it is easier to avoid errors and differences between the scripts.
Even in the more restricted case, if you update function in library - as long as you are already calling it in the app - all you have to do is select the new version of the library used.
I hope I had anything to give in this conversation and my language was appropriate, this was my first answer..
A good question Melly. I've been through a bunch of the documentation and some tutorials on this subject but haven't tried adding any libraries yet. My understanding is that once you are connected to a library all you have to do is call the applicable functions. That once a library is connected the functions in the library become an extension of all the other Apps Script classes available in the script editor.

How can I let others install my Google Apps Script?

I've made a simple script in Google Apps Script. The script builds forms based on a spreadsheet, the script itself is part of the spreadsheet. It adds a menu item. People would like to use it. They are non-technical people, so I would like to make the installation of my script as easy as possible. With 'installation' I mean a way to 'import' my script into their spreadsheet and automatically set up the needed triggers so the menu item becomes visible. It should be possible for anyone to install it.
I've been thinking of the following solutions:
Publishing as an add-on: my script wouldn't qualify, and even then I can't wait for Google's approval.
Copy-paste. I don't like this, it's way too complicated.
I've looked at this question: https://stackoverflow.com/questions/5334751/how-do-i-share-a-script-i-wrote-with-my-co-workers-on-the-same-google-apps-accou, but the people wanting to install it are not on the same domain in my case. The question is also 3 years old.
EDIT: As it turns out, there doesn't seem to be a solution. I've filed a feature request here: https://code.google.com/p/google-apps-script-issues/issues/detail?id=4122&thanks=4122&ts=1403949074
If your Google Account administrator allows you, you can share scripts/spreadsheets outside your organisation either by sharing directly with another person with a Google Account (Gmail or Google Apps) or by making it public (share with a link or published online).
https://support.google.com/drive/answer/2494822?hl=en
Keep in mind that if you use the Script Properties to store values, each time someone uses the shared script it will overwrite the values. In a shared context it is best to use User Properties instead. This way each user can store their own values.
https://developers.google.com/apps-script/guides/properties
There is no way to import a script in an existing spreadsheet , the "normal" workflow is , in a way, the reverse process, that's to say create a sheet from an existing template that already has the script in it and start to work with that copy.
From your description I'm not sure this method could be useable but I'm afraid there is no other way if you want people who will be using it should not go into the script editor at all.
There would be a couple of functions to write that should run at install time and would create the triggers (if needed) and trigger the authorization process.
I made such a SS some time ago that needed authorizations and I added an "install" menu that made its use quite simple (example here on a friendly hosting site).
I know this is probably not the answer you were expecting but it was definitely too long to fit in a comment anyway.

Spreadsheet Editor's Ability to Run Scripts from Library

I will be maintaining Google spreadsheets for 100 different schools. Each school's spreadsheet will have similar functions (e.g., jumping to a certain cell based on the date or creating a note in a certain cell based on inputted text) and multiple people will have access to edit it (e.g., principal, teachers, coaches, etc). I imagine that creating a library is easiest for this purpose since the functions are the same for each spreadsheet! For example, the script file for each document uses the onOpen() event to call .addMenu(). Then .addMenu calls a wrapper function and this function calls the "jumpToToday" method in my library. (I saw the posts about how the library method cannot be called directly from the menu, so that is why I did it this way). I have two questions:
When I (the owner) share the spreadsheet with an editor, the menu shows up, but when the editor selects one of the menu options, the script returns the error:
You do not have access to library ExternalSupport, used by your script, or it has been deleted.
After I saw this, I shared the library file (Can View) with the spreadsheet editor and then it worked. Do I have to share the library (view only) with ALL editors of the spreadsheet so that they can run the functions? If so, that's fine (I was just trying to avoid it because most principals/teachers/coaches are not techie, so I didn't want to confuse them by sharing a file of code...I just want them to use the spreadsheet).
Because the editors of the spreadsheet will only be able to view the library, it seems like they only have access to the Version that is selected (even if dev mode is on).
When I update my library to another version, do I have to go into the Script Editor of all 100 spreadsheets and then go to Resources > Manage Libraries and update the version? Or is there a way to make all files use the latest version of the library?
1) Yes. According to the documentation
you must grant at least a read-level access to your project for all potential users.
I agree that this may be confusing for other users but at the moment it is necessary.
2) There is no way to make a file use the latest version of a library. Though, there is a way to make a file use the development version of a library. For this to work you need to grant editor-level access to your library to the user. However, bear in mind that any changes that you make to the library will be reflected immediately at the user's end. You can find more information in the documentation.