Question
How do you edit two different spreadsheets from one connected script that is triggered by an onEdit command?
My Case
I am trying to create a master spreadsheet that sends and deletes information to two other spreadsheets. I have an onEdit function that once a checkbox is checked, it will send specified information to another sheet.
What I've Tried
To open the other spreadsheet I first tried the openByID function but through a little research I don't believe it is possible to edit another spreadsheet through a script that is bound to a spreadsheet. So I created a standalone script (named MasterF) that I deployed as a library to store my function so that I can call it later. I added the library to the master spreadsheet and am using it to call the function but it keeps throwing an error saying, "You do not have permission to call SpreadsheetApp.openById." All of my apps scripts have full permissions to edit, delete, etc. I've also made libraries out of the scripts bound to the other spreadsheets I want to connect and added those libraries to the MasterF library to see if that would help. I still get the same error message when the on edit function, despite trying to use a standalone script. Maybe I missed something, or it is entirely possible that I can't do what I'm trying to do.
Script
This the beginning of the custom function that I created. Essentially when an onEdit function is triggered, data from spreadsheet1 in the "submit" sheet, is transferred to spreadsheet2 in the "dashboard" sheet.
function DataSend() {
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var submit = ss.getSheetByName("Submit");
var selldata = submit.getRange('E23:I23').getValues();
//#NotOnlyCurrentDoc
var dash = app.openById(<sheetid>).getSheetByName("Dashboard");
Here's the onEdit Function in the script that is bound to spreadsheet1 (not directly a part of the MasterF library) that triggers the datasend function that is kept in the MasterF library.
function onEdit(e) {
var sheetName = "Submit"
var range = e.range;
if (range.getSheet().getSheetName() == sheetName && range.getA1Notation() == 'K23' && range.isChecked()) {
MasterF.DataSend();
}
}
To edit two different spreadsheets from one connected script that is triggered by an onEdit command, you need to install a trigger. A simple trigger does not have the permissions required to edit multiple spreadsheets. Ref. In my question I was trying to use a standalone script and multiple libraries. This is unnecessary. All you need to edit multiple spreadsheets from a single script is an installable trigger.
In my case, I used the following function to create an installable trigger:
function EditTrigger() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ScriptApp.newTrigger('Edit')
.forSpreadsheet(ss)
.onEdit()
.create();
}
'Edit' is the name of the onEdit function I used to detect the changes made in the first spreadsheet. If an If statement in the onEdit function is true, then it runs a separate function that edits two different spreadsheets. After writing the EditTrigger() function, run it manually in apps script and accept permissions if necessary. Now, when the onEdit function ('Edit') is triggered, it should be able to edit multiple spreadsheets.
Related
Built a website on Google App Script (for ref its on michelmoalem.com).
On page load I populate several vars with verious text blobs read from docs stored on google drive (CV, Biography etc) I use a pair of functions for each blob - on the JS script that - the first one (in this example loadEditor) runs the function getDocContent from the main code page (server side script) and on success feeds the resulting blob to the second function (loadCvData) that populates the var (cvEditing) with the aquired text.
function loadEditor(fetchResults){
google.script.run
.withSuccessHandler(loadCvData)
.getDocContent('16rvULQudFCcdJOb32Qk7qqfOfWmTxJ7MPuQ_fZJhaf4');
}
function (fetchResults2){
cvEditing=fetchResults2;
}
what I was wondering is how to populate the var within the first function eliminating the need for this 2 step solution...?
Perhaps:
function loadEditor(fetchResults){
google.script.run
.withSuccessHandler(function(data){loadCvData(data);let cvEditing=fetchResults;})
.getDocContent('16rvULQudFCcdJOb32Qk7qqfOfWmTxJ7MPuQ_fZJhaf4');
}
Explanation:
You need the success handler in order to handle data coming from server-side via google.script.run and use it client-side, that's how Apps Script works. At most you can use an anonymous function in the success handler, instead of calling another function, but that's it.
I am trying to get the content of a cell's formula from a custom function that I wrote. I'm just trying to get the formula stored in B2. In Google Sheets. I am getting "Exception: Authorization is required to perform that action. (line 5).". I tried revoking the authorization, adding the next first three lines and authorizing again. Nothing worked.
/**
* #OnlyCurrentDoc
*/
function test() {
return SpreadsheetApp.getActiveSheet().getRange('B2').getDataSourceFormula().getFormula();
}
I can confirm that the error is coming from getDataSourceFormula(). I tried replacing it with other functions, and they worked normally. What is the problem?
Thanks.
You are using incorrectly getDataSourceFormula() as you are combining it with getFormula().
getFormula() returns the top left cell formula of a range while getDataSourceFormula() returns the DataSourceFormula for the first cell in the range. Thus, getDataSourceFormula will only work for data sources, here is more official information regarding what these are.
As you didn't mention anything about data sources in your question I am assuming that you are not using them and therefore you code line should look like this:
return SpreadsheetApp.getActiveSheet().getRange('B2').getFormula();
I have two google spreadsheets, a master copy and a child copy. When I update the formulas in the master copy, I want it to update the formulas in the child copy too. I intend to create many copies of the child copy and don't want to update the formulas in each one every time something small has to change.
I've tried using IMPORTRANGE(), and it only gives me the values, not the formulas. So I thought to create my own script to get this done. I'm using the following code to attempt this:
function REMOTEDATA(inKey, inRange) {
var outData;
var ss = SpreadsheetApp.openById(inKey);
if (ss) {
outData = ss.getRange(inRange).getFormulas();
}
return outData;
}
//My manifest is the following:
{
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets"
],
"timeZone": "America/Denver",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER"
}
I'm very new to oAuth and I don't understand how to get this to work. When I attempt this it gives me the following:
"You do not have permission to call SpreadsheetApp.openById. Required permissions: https://www.googleapis.com/auth/spreadsheets (line 4)."
Can anyone tell me what I need to add to get this to work? If there's an easier way, I'm all ears.
EDIT:
After reading Ruben's comment below, I changed the way I was doing it to having a button on the sheet itself run the function. It fixed the first problem, but now I'm running into another problem. I can't copy all the data directly from one sheet to another. I'm trying to get formulas, values, and formatting. If I just use getFormulas() and setFormulas() with the ranges, it gets rid of all the values that aren't formulas, and it doesn't change the formatting. I've been trying to use copyTo() but it tells me I can't do this between spreadsheets. My current code is:
function REMOTEDATA() {
var MASTERKEY = "key";
var UPDATERANGES = ["A1:B200", "C7:C200", "D1:H200", "J1:L200", "N1:S200", "U1:X200", "z1:ac200", "AE1:AH200", "AJ1:AL200"];
var ss = SpreadsheetApp.openById(MASTERKEY);
var cur_ss = SpreadsheetApp.getActiveSpreadsheet();
UPDATERANGES.forEach(function(range) {
data = ss.getRange(range).copyTo(cur_ss.getRange(range));
});
}
My head is starting to hurt looking at the different methods for the Ranges Class. I can't see any methods to do this, but I feel like I'm missing something. Any other ideas?
EDIT 3:
Okay. I figured out a workaround. Basically what I did was copy the entire sheet from one spreadsheet to the other using the sheet.copyTo() function. Then after that I used the range.copyTo() to get what I wanted. Then I deleted the copied sheet using sheet.deleteSheet()
Custom functions run anonymously so they can't call services that require authorization, like openById.
Instead of using a custom function to execute your script use another method like a custom menu, assign the script to an image, etc. or just run it from the script editor.
NOTE: You will have to modify your script a bit or use a another function to pass the required arguments.
I want to display a message on a google sheet. But I don't get it, and, after research here, in documentation, I don't get the answer.
I think that the problem is in "activate" the spreadsheet, where i need to display.
var SEGUIMIENTO = SpreadsheetApp.openById("MyTestediD");
var INF = SEGUIMIENTO.getSheetByName("NameOfSheet");
function TestMessage() {
INF.activate();
Browser.msgBox("Hello")
}
When i run.. nothing happen
I need the definition of Spreadsheet outside the function because I'm working in 2 Spreadsheet's by ID in more that one function.
i only need the correction in my code for display a simple message in the spreadsheet.
PD. i really cant find a simple example of that,
Update
This code it's part of a macro recorder of a Spreadsheet, the same "SpreadsheetApp.openById("MyTestediD");"
I don't know why you try to 'activate' a sheet. If you want display a message I assume you want to do it in the user's current sheet, so:
SpreadsheetApp.getUi().alert('Confirmation received.');
From https://developers.google.com/apps-script/reference/base/browser
The methods in this class are only available for use in the context of a Google Spreadsheet. Please use G Suite dialogs instead.
As you can see, Google is nicely asking you to use G Suite dialogs instead of Class Browser, so be nice too and follow their request.
When you say you want a message in a spreeadsheet, do you mean an alert message? If so, the answer is to use the code SpreadsheetApp.getUi().alert('Hello.'); when the TestMessage function is executed
var SEGUIMIENTO = SpreadsheetApp.openById("My TestediD");
var INF = SEGUIMIENTO.getSheetByName("NameOfSheet");
function TestMessage() {
INF.activate();
SpreadsheetApp.getUi().alert('Hello.');
}
I'm trying to learn Google Apps Script, and I just did a bit of an experiment with creating two ".gs files" in the same project, each with an onOpen() function.
After saving, closing, and then opening the document, only one of the onOpen() functions ran (the Sidebar.gs file).
Do these need to be included in the same file? Well, I guess I know that it is a work around. I guess my question is WHY?
Project:
Code.gs:
function onOpen() {
DocumentApp.getUi().createMenu("PACKT").addItem("Greeting","greeting").addToUi();
}
function greeting() {
var ui = DocumentApp.getUi();
ui.alert("Greeting", "Hello World!", ui.ButtonSet.OK);
}
Sidebar.js:
function onOpen() {
var htmlOutput = HtmlService.createHtmlOutput('<button onclick="alert(\'Hello World!\');">Click Me</button>').setTitle("My Sidebar");
DocumentApp.getUi().showSidebar(htmlOutput);
}
Thanks!
You should never have two functions with the same name in the same namespace. It simply doesn't make sense: which of them should be executed when functionName() call happens? (In reality, the function that was last to be defined will be the surviving one; with the rest lost without trace).
In particular, you should not have two onOpen functions within the same project, be it one file or separate (the files share the namespace, meaning that the functions in one file can be called from the other as if they were in the same file).
But your one onOpen() function can simply call whatever functions need to run:
function onOpen() {
doThisThing();
doAnotherThing();
}