Where to save GAS to be accessed via several spreadsheets? - google-apps-script

I have written a script inside spreadsheet, that is triggered on spreadsheet-form-submit.
However, since I have several such similar spreadsheet, I would like to place the code at one central location and link/import in each spreadsheet. (That is, I want to maintain one copy of code, where-in if I make improvements, it should auto-magically be reflected in each spreadsheet).
Thanks.

Place your code in a standalone script (create it from the Create>More>Script menu in Drive or just from script.google.com). In each spreadsheet, add a script that just includes your first script as a library and delegates onOpen, etc. to the functions in the library. When you update the standalone script you'll need to go into each spreadsheet and update the version number of the library to be the latest version, but that's all.

Related

how to share same app-script between multiple (different) spreadsheets in google spreadsheets

First of all I am after 3hours of reading docs about google cloud, publishing, projects and so on. After many tries i realized that i am missing something so here is my question.
I have two spreadsheets, lets, call it "prices" and "costs". What i want to achieve is that they share same app scripts and if I change one script, since it is shared by both it will automatically change in secons.
So i did create an app script that returns a string (just for simplicity) in a cell and called it STRINGFUNCTION(); Is is created in PRICES spreadsheet. My goal is to have it working in COSTS file without typing it manually.
I expected that if i click Resources > Cloud Platform Project and add both app scripts from both spreadsheets to the same project it will work automatically. Well, it wont - if i write in a cell =STRINGFUNCTION() in PRICES it works fine, and in COSTS - it says that function in not known.
How can I achieve that so it works between my both files and they share same function if they are both in same project?
You can do this by putting your code in a standalone script and use it as a Library.
https://developers.google.com/apps-script/guides/libraries
Here's how to do this:
Go to https://script.google.com/ and create a new project
Replace the code with the code for your custom functions and save
Click "Untitled Project" and give it a name to use for accessing the library
Click the blue Deploy button and choose New Deployment
Click the gear beside Select type and choose Library
Enter a description and click Deploy (this is what makes your Library available from other scripts)
Go to Project Settings and copy the script ID
Go back to your Spreadsheet, open the script for your sheet, click + beside libraries and paste the script ID and click Add
Remove the code for the custom functions if necessary and you're going to create functions to pass through the library functions
If your function is called STRINGFUNCTION(), create a function in the local apps script like this:
function STRINGFUNCTION(parameter) {
return libraryName.STRINGFUNCTION(parameter);
}
Do that for each function you want to use from the Library and save your code. You will need to authorize permission for the script if you haven't already. Now the custom functions should be available in your spreadsheet. Copy and paste this "pass through" script to each sheet where you want to be able to access the custom functions from the Library.
Custom functions inside a Library cannot be called directly from a sheet. You only have to set up this local script to pass through the functions, once. Now if you update the script in the Library, the updated functions will be available to the sheet. You will need to do the deploy set each time you make a change to the Library to publish the changes. If the changes aren't working in the sheet, click on the Library in the local script and make sure the version is Head or the latest version you published.
You can only bind a Google Apps script file to one document at a time. Apps script doesn't allow you to edit the contents of a .gs file on the cloud from inside another Apps script file, as trying to fetch:
var data = DriveApp.getFileById('script-id').getAs('application/vnd.google-apps.script');
will return the error:
No item with the given ID could be found, or you do not have permission to access it.
You could however bind the script to one spreadsheet, for example say the 'COSTS' spreadsheet, and create a second sheet within the spreadsheet for 'PRICES' with all the relevant function calls. In the separate 'PRICES' spreadsheet you could then use the build-in IMPORTRANGE formula to get the data from the 'PRICES' range from the first spreadsheet that has the bound script.

How to change a "bound" Script to a "Standalone" script?

I have a Google Sheets script that's bound to a specific doc. Basically it takes the results of certain cells, then it used these values in doc.
I have multiple Sheets I'd like to "attach" to this script. All the other Sheets have the exact same tabs and cell names, etc.
Is there a way to turn that bound script to a standalone script, then attach them to the other Sheets?
You cannot unbind a bound script:
The file a bound script is attached to is referred to as a "container". Bound scripts generally behave like standalone scripts except that they do not appear in Google Drive, they cannot be detached from the file they are bound to, and they gain a few special privileges over the parent file.
To use the functionality you've created, you'll want to export the bound script as a library and import it in the other spreadsheets' script editors. You may also have to do some tweaks to get any UI alterations
Note that an installed library will not automatically update the used version, so if you make changes to your library source and save a new version, you'll have to go through all the spreadsheets that reference it and update the library version.
The alternative to a library is to go through the process to publish your script as an add-on. This will let you redeploy your changes without needing to go through every single spreadsheet.

Noob: Make my scripts available to me

Sorry for the dumb question, I have tried to search but did not find an answer. Please point if the answer is already been answered.
I am practicing writing my first google scripts (apps). If I create them from within a sheet they are only available to that sheet (bound). I can create them by creating a new script but I don't know how to make them available to all of my spreadsheets (not just one). THe scripts I downloaded from the store show up but how do I add my scripts.
I do not want to publish these to the world, I just want them available to me so I can access them from any sheet I am working with.
Basic question but I am having trouble understanding the process.
Thanks,
A script bound to a spreadsheet is only available from that sheet, you won't be able to access it from another sheet.
You can also create a script file (not related to any other document) but this will not be available from sheets.
This is how it is meant to be.
One thing you can do to use functions you eventually develop in a script is to make a Library of it, the functions in that library will be available to other scripts if you explicitly link the new script to the library (in the script editor > ressources>library) but this procedure is not as simple as the workflow you imagine in your question : each document will have to contain a minimal piece of code that will call the script library functions.
The last option to get create a "spreadsheet-with-script" and to simply make copies of this original spreadsheet (that has a script) and that copies will have the script copied as well.

How can I invoke my standalone script in my spreadsheet?

I have created a standalone Apps Script from Google Drive, but when I try to access it from a Google Spreadsheet, I don't see a way to access the script (even though when I created the script, I created it as a spreadsheet script).
In the spreadsheet, the "Tools->Script manager..." menu item doesn't show my script, nor does the "Tools->Script editor...". The latter has a section for 'recent projects', but it doesn't list my newly created script, nor its associated project.
If I create a new script from inside the spreadsheet (i.e .Tools->Script editor...) and cut and paste the code from the standalone script, it works fine. However, this can only be used in the single spreadsheet -- to use it from another one, I have to cut and paste / go through auth again.
Is there a way to do this without publishing the script to the gallery, which I assume makes it public (I don't have a problem making it public, but it seems like there must be a better way)? The script is here -- it is world readable with the link. It adds a menu to a google spreadsheet that lets you run a query in BigQuery and dumps the results into your spreadsheet.
The behavior you describe is exactly how it is intended to work... the script you wrote can only work if it is bounded to a spreadsheet.
The fact that you wrote it in an independent script makes it indeed a standalone app but it can only be executed from within the script editor and in this context an onOpen function like the one you wrote doesn't make sense (it runs on opening a document/spreadsheet, not the script).
For now a script can only be bounded to a spreadsheet by copy/pasting the code, at least a script that you want to use as you do (with a menu and direct function calls and activeSheet calls), maybe one day Google will expand the concept of libraries to make your script function available from different document directly (read also the doc about libraries).
There are actually 2 types of standalone Apps Scripts, the one you tried that runs only from within the editor and webapps that are deployed and run in a browser window by themselves. The latter are always build around a doGet function that represents an entry point for the application. You should read the documentation on the subject to get all the details.
To summarize : if you want to access your spreadsheet using getActiveSpreadsheet() and similar methods then you have to write (or paste) the script in the script editor bounded to the spreadsheet.
If you want to have a standalone script you can also interact with spreadsheets (and other document as well) but you have to access them by their ID and the spreadsheet will only be viewable from another browser window, without link between them, and there will be no "active spreadsheet" nor "active sheet"...
A webapp can of course also do that with the advantage of a user interface that you can adapt to your needs but this is becoming a bit too far from the scope of your question.
Hoping I've made it (a bit) more clear, at least I tried to make it simple ;-)
I worked this out with Jordan, following the instructions here:
https://developers.google.com/apps-script/guide_libraries
First, he had to share his standalone script with me, so I had read access to it (probably setting the script as public read would work too).
Then he told me his project key.
I took his project key and inserted it in "Find a Library", in the "Manage Libraries" menu.
For this to work, Jordan had to export "a version" of his library - so third parties can rely on stable code and upgrade at their own rhythm.
As Jordan's script runs automatically on onOpen(), my code had to define a function onOpen() that called his script onOpen(). To do this, the library manager gave me an identifier for the imported library.
Sample code once the library is imported and the library manager gives you an identifier for the library:
function onOpen() {
GivenLibraryIdentifier.onOpen();
}
You can also use installable triggers. If you install an installable trigger (such as onOpen) from your standalone script into the document, it gets similar privileges as if it were a simple trigger.
And better yet, when the installable trigger calls its function from your standalone script, it executes WITHIN your standalone script! So it can call any other function in your standalone script. Its Logger.log() entries can even be viewed from your standalone script, even though it was executed from your sheets document.
So basically, if your script installs an onOpen() trigger tied to one of its functions, it's as good as if your Sheets document had required() your whole standalone script file.
(Assuming the owner of the script has edit privileges to the file.)

Is it possible to have one script for multiple spreadsheets?

I have one master spreadsheet and a number of copies. This master spreadsheet uses some scripting.
Is it possible to link all the copies of this master spreadsheet to the same script as in the master spreadsheet?
Objective:
changes in the scripting in the master spreadsheet are automatically used by the copies
aka: low maintenance
amleczko is right: you should use the new library feature in Google Apps script.
However, as of today, you won't be able to do exactly what you want (using the same script for several spreadsheets). What you can do instead is save a version of your script (Files > Manage Versions...), in order to create a library. Then, import this library in the other spreadsheets (Resources > Manage Libraries...). Switch on the "development mode" so every change made do the library will immediately take affect in the spreadsheets using this library. Otherwise, you will have to save a new version of the library for every change, and manually update the version number of the library in every spreadsheets using it.
The problem is, you need to write a script in every spreadsheets using your library, with skeleton functions like this:
function doSomething(){
myLibrary.doSomething();
}
best way is to publish as add-on, then install the add-on, it will appears in every spreadsheet you open. and you can publish as private, which only seen by yourself.
I think this has changed. According to Issue 40 starting from 22 May 2012 there is such a possibility. Please check:
https://developers.google.com/apps-script/guide_libraries
https://developers.google.com/apps-script/guide_versions
http://googleappsdeveloper.blogspot.it/2012/05/introducing-versions-and-libraries-in.html
It's not possible in this way that you're thinking. At least, not yet (see issue 40).
But, depending on your script usage, you may connect them "the hard way" or even better, use only one script. The script on the master spreadsheet can open the other spreadsheet files and do its job "remotely". It's not required that script to be hosted on a spreadsheet to interact with it (read/write on it). You only need a script hosted on the spreadsheet if you're going to use spreadsheet events triggers i.e. on-open, on-edit and on-form-submit.
Maybe you can develop a nice UI for the script on the master sheet and publish it as service. Then only have a link on the copies to access the same UI on a different browser tab. Adding parameters to the link the script UI can even adapt to the particular spreadsheet that is "triggering" it.
Well, that's all I can imagine now. But, unfortunately, there's some use cases that just don't fit this nice "workarounds". For those, one can only star issue 40 (to kind of vote and keep track of updates) and hope it's developed soon.
The solution I put in place in this context was to have a Google Site, where the Master Script is embedded, and where the Spreadsheet is embedded too
Then, the script, refering to a dedicated spreadsheet, looks for the Google Site Page's name, looks in the Master spreadsheet and get the ID of the spreadsheet which is embedded in the Page.
I have solved this problem when using a script which auto generates spreadsheets.
Typically, I will add a sheet to any spreadsheet with a script called "Info." I'll use that to store information that it important to the script. In my script which auto generates more spreadsheets, I keep track of the ID of the created sheet. This way, I can then quickly call up all of the "linked" sheets, and interact with them with using the same script. It might even be worth writing the script in one sheet, and keeping it totally separate from your Master sheet or it's children.
Take a look at this function, it might give you some ideas.
SpreadsheetApp.openById(id)