Writing into another Spreadsheet with SetValue fails without errors/exceptions - google-apps-script

I'm trying to update a spreadsheet from a script running on another spreadsheet.
Nothing seems to have any effect on the table (SetValue(), SetBackgroundRGB(), etc.).
I've checked the scope, it includes "https://www.googleapis.com/auth/spreadsheets" permission; besides, this same script has no problem writing to another spreadsheet that it creates in runtime.
function updateAnotheSpreadsheet() {
var targetSpreadsheet = SpreadsheetApp.openById('<target spreadsheet id>');
var sheet = targetSpreadsheet.getSheetByName('<sheet name>');
Browser.msgBox(sheet.getRange("A1").getValue()); // Here I see that my getSheetByName worked
sheet.getRange("A1").setValue('Test value'); // But this does nothing
}
There are no errors but also no effect: nothing changes in the target spreadsheet.

Hi I was testing and was able to do what you are trying to do. You can try to declare a variable for the message, here is what I was able to do, I hope this resolves your inquiry.
function updateAnotherSpreadsheet() {
//Opening the second Spreadsheet by ID
var targetSpreadSheet = SpreadsheetApp.openById("<SpreadSheetId>");
var sheet = targetSpreadSheet.getSheetByName("<SheetName>");
//Getting the range to show on msgBox.
var msg = sheet.getRange("A1:A1").getValue();
//Displaying old data on A1:A1 from the secondary Spreadsheet.
Browser.msgBox("Old data on secondary spreadsheet: " + msg);
//Getting the range and setting new values
sheet.getRange("A1:A1").setValue('Test value').setBackground("teal").setFontColor("white");
}
I would suggest to check for more information here https://developers.google.com/apps-script/guides/sheets.
I hope this helps, greetings.

I found the problem.
A function called from OnEdit() can't ask for permissions. I needed to first update that other spreadsheet from any function called by something "active", like a button; then, after the script asks for permission once, it can do its thing from OnEdit() the next time it runs.

Related

How to import data from a different workbook, with a button. getSheetById(id) doesn't work

I want to import data from 3 sheets in a different workbook, in the same drive, to a newer workbook, with the press of a button.
Each workbooks has a sheet called 'Log Wizard' with 2 boxes. The bottom box displays the current spreadsheet key. The top box is an input field to paste an existing sheet key into.
https://docs.google.com/spreadsheets/d/1833-5CnOurssETuZFtohiHRRBx1V3_95_L0S-f9vPLk/edit#gid=187106606
enter image description here
enter image description here
So far, I cannot figure out how to make a script that does the following:
When the button is pressed, get the source sheet id which is provided by the user in cell M11 of the current sheet, and use that to access the referenced spreadsheet
And then copy 3 different ranges from three different sheets (2 of which are hidden) to empty sheets of the same names in the newer workbook (vehicle configuration, budget log and log).
I know that getSheetById has issues with permissions of some sort. I am not very familiar with google scripting so any help is appreciated.
//variables
var id = "123456789abcdefg";
var sheet = "LOG WIZARD";
var cells = "M11:AB13";
var range = SpreadsheetApp.openById(id).getSheetByName(sheet).getRange(cells);
var id = range.getSheet().getParent().getId();
//custom function to import logs
function importlogs() {
//Source sheet from which to import from
var is = SpreadsheetApp.openById(id)
var sheet1i = is.getSheetByName("BUDGET LOG");
var sheet2i = is.getSheetByName("LOG");
//Current sheet from which to export to
var xs = SpreadsheetApp.getActiveSpreadsheet();
var sheet1x = xs.getSheetByName("BUDGET LOG");
var sheet2x = xs.getSheetByName("LOG");
//Copy and paste contents of import Budget Log sheet to export Budget Log sheet
sheet1i.getRange("A3:AO").copyTo(sheet1x.getRange(sheet1x.getLastRow()+1,1,1,7), {contentsOnly:true});
//Copy and paste contents of import Log sheet to export Log sheet
sheet2i.getRange("A3:O").copyTo(sheet2x.getRange(sheet2x.getLastRow()+1,1,1,7), {contentsOnly:true});
}
I am unsure if it is actually passing the key correctly or at all. I tend to get the error Exception: Unexpected error while getting the method or property openById on object SpreadsheetApp. or Exception: You do not have permission to call SpreadsheetApp.openById. Required permissions: https://www.googleapis.com/auth/spreadsheets (line 5).
I assume this is because of some type of permission that doesn't allow a custom function to call another spreadsheet?
I have tried various suggestions here:
You do not have permission to call openById
and here:
How to use an installable trigger to get SpreadsheetApp.openById(id) to work, by calling it from a cell
but so far nothing I have found works.
The //variables section is in the global scope of the script project, so those definitions get evaluated every time any function runs, just before the function executes.
The problem is that those definitions are not compatible with the custom functions you are using. A custom function runs in a limited context where methods that require authorization are not available. When SpreadsheetApp.openById(id) gets called in that context, the custom function errors out, even though the problematic line of code is not within the function itself.
The importlogs() function is run through a button. It will run in an authorized context where SpreadsheetApp.openById(id) is available normally.
To solve the problem, delete the //variables section. The same declarations are repeated within importlogs(), so that should be enough. If you want to improve the importlogs() function, use the code given to you in your previous question.
You may want to add this code to easily call the importLogs_() function through a button:
/**
* Call this function through a button.
* https://developers.google.com/apps-script/guides/menus#clickable_images_and_drawings_in_google_sheets
*/
function runImportLogs() {
const sourceSsId = SpreadsheetApp.getActive()
.getRange('LOG WIZARD!M11')
.getDisplayValue();
importLogs_(sourceSsId);
}

How to make each function run on specific page?

I have two fuctions with same name "myFunction" I run it using google trigers on edit, and I have two sheet how to specify each one for each sheet I use this but it doesn't work
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Copy of Timesheet & Feedback");
//and on the other function
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Visits");
Problem:
getSheetByName() will return the sheet you're looking for, but has nothing to do with the sheet that is being edited to trigger your function.
Solution:
Instead you can use event objects for this purpose. Wrap your whole script inside an if statement checking the name of the sheet. The new function should look something like this:
function myFunction(event) {
var ss = event.range.getSheet();
if (ss.getName() === "Copy of Timesheet & Feedback") {
//your code here
}
}
This way the code will not continue if it doesn't find the sheet it's expecting (the sheet name inside the if statement).
Notes:
Notice the name of the function myFunction(event), "(event)" is important so that we can access the event object to grab the spreadsheet that is being edited.
You won't be able to run the script manually, set up a trigger for "on Edit" and it'll just run automatically.
References:
Event Objects

How do use the addEditor method on a protected google sheet

Please help. This is all new to me.
I have a protected sheet in a google spreadsheet that I want to leave protected. However, my script deletes rows and adds rows to that protected sheet. It works great for me, but other other users cannot run the script.
I tried creating an onOpen trigger that calls a function which uses the addEditor method for those users. However, that did not work. To test my trigger, I changed it to the following which calls a function called UserInfoFunction, also shown below , wherein I get a messagebox telling be who the Effective user is and who the Active User is. I thought the Effective user should have been me since I created the script. But when others run this the message box shows they are the Effective user which, I'm assuming is why my addEditor function is not working since the Effective user wouldn't have permissions to change the protection...What am I doing wrong.
function createSpreadsheetOpenTrigger() {
var ss = SpreadsheetApp.openById(".......");
ScriptApp.newTrigger(UserInfoFunction())
.forSpreadsheet(ss)
.onOpen()
.create();
}
function UserInfoFunction() {
var me = Session.getEffectiveUser();
var them = Session.getActiveUser();
SpreadsheetApp.getUi().alert('me is equal to...'+ me + ' user is equal to ' + them);
}

create and bind onEdit script to spreadsheet from inside form-bound script

I'm having a bit of trouble with this code, this is a script bound within a Google Form and triggered on Form Submit:
function onFormSubmit(e) {
//these lines are to get the email address that was entered into the form
var familyResponses = e.response.getItemResponses();
var familyEmailAddress = familyResponses[0].getResponse();
//this loads the template spreadsheet
templateSpreadsheetFile = DriveApp.getFileById("xxxxxxxx");
//this generates an 8-digit random number
var eightDigitCode = Math.floor(Math.random() * (99999999 - 10000000 + 1)) + 10000000;
//this makes a copy of the template spreadsheet, with the 8-digit code as the name of the copy, in the specified folder.
var FamilyWorksheetsFolder = DriveApp.getFolderById("yyyyyyyy");
var newSpreadsheetFile = templateSpreadsheetFile.makeCopy(eightDigitCode, FamilyWorksheetsFolder);
newSpreadsheetFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT); //this allows anyone with the link to view+edit the new file
//now we need to add a script to the new spreadsheet, that makes a copy every time it is edited
ScriptApp.newTrigger('familyWorksheetScript')
.forSpreadsheet(newSpreadsheetFile)
.onEdit()
.create();
//these lines build the subject and body of the email
var emailSubject = "link to your worksheet";
var emailBody = "Here is the link to your worksheet: \n" + newSpreadsheetFile.getUrl() + "\n\n\
Your spreadsheet is named with your unique 8-digit code " + eightDigitCode
//send the email
GmailApp.sendEmail(familyEmailAddress, emailSubject, emailBody);
}
function familyWorksheetScript() {
}
==============================================
The idea here is pretty simple:
family fills out form (one question: what's your email address?) and submits
onFormSubmit script runs (installed trigger), gets email address, generates random 8-digit code, makes a copy of a template spreadsheet, the copy is named with the 8-digit code. puts it in the right folder, and sets the permissions.
then the family is emailed with a link to the spreadsheet
All the above works. But I would now like to add the feature, from within this form-bound script, to create an on-edit triggered script bound to the new spreadsheet (copy of template, named with 8-digit code). And this is the part that I can't get to work. It's the ScriptApp.newTrigger code block, when I comment it out, the whole script runs fine I get the email at the end. But when I leave in the ScriptApp.newTrigger code uncommented, the script dies right at that spot. I can tell it's dying there because the new spreadsheet still gets created, but the email doesn't get sent. I don't know why it isn't working and I don't know how to troubleshoot it.
Any help would be much appreciated. Thanks!
You can't creat a trigger on a sheet that would act as the new sheet user, everything you create belongs to you ! the triggered function would run as "you", not the new user.
What I would suggest id to create an "onOpen" function with a UI that would ask for the new user to click on a "button" to run a function that would create the onEdit trigger, asking them for explicit authorization.
Edit
below is a sample code with an onEdit trigger working on the copy of the active spreadsheet, just for test purpose.
function createNewCopy(){
var ss = SpreadsheetApp.getActive();
var newSs = DriveApp.getFileById(ss.getId()).makeCopy('copyOf-'+ss.getName());
var nSs = SpreadsheetApp.openById(newSs.getId());
var trigger = ScriptApp.newTrigger('onEdit').forSpreadsheet(nSs.getId()).onEdit().create();
}
the onEdit in the original SS is as simple as that, just to check it works :
function onEdit(){
Browser.msgBox('hello');
}
note that no trigger will be viewable in the spreadsheet's script editor ressource tab, it will only appear in your own triggered function list in your Google account.

Why doesn't the trigger work for the script running a function on my google spreadsheet?

So I'm using a script on my googledoc spreadsheet that goes through a column and counts a certain number of occurrences of specified formatting. (i.e. in my spreadsheet "=myFunction()")
The function works fine, but my problem is despite setting up a trigger to run the script "onEdit", it never does it. I have to open the script up and save it each time I want it to update on my spreadsheet.
I've been looking up for hours but no one seems to have my question. There are no errors sent by the notifications. The code (though I don't think it's terribly relevant) for my function is:
function CountIfNotStrikeThrough2()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var mysheet = ss.getActiveSheet();
var mydatarange = mysheet.getRange(1,1,390,1);
var numRows = mydatarange.getLastRow();
var rowindex = mydatarange.getRowIndex();
var columnindex = mydatarange.getColumnIndex();
var total =0;
for(i=rowindex;i<=numRows;i++)
{
if(mydatarange.offset(i-1, columnindex-1, 1, 1).isBlank() != true && mydatarange.offset(i-1, columnindex-1, 1, 1).getFontLine() != "line-through")
{
total++;
}
}
return total;
}
I know there's a thread here that has a comprehensive list of when the onEdit trigger doesn't activate. (here) For example, if you setup Data Validation and select an item from the list of values in the validation, it doesn't trigger the onEdit function.
Besides that, could you try a simple trigger instead of installable? This is to say, instead of explicitly associating CountIfNotStrikeThrough2() to the onEdit trigger, please try re-naming the function to "onEdit()" instead and see if that works. This creates an implicit or simple trigger. I've had trouble in the past with installable vs. simple triggers.
Also, please share the exact action you're performing to test the trigger.
Reference: https://developers.google.com/apps-script/understanding_triggers