Clear content in specific cell using Google App script - google-apps-script

I have write app script as below, I am stuck with this error "TypeError: Cannot read properties of undefined (reading 'range')"
function clearContent() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Filter Tools")
var r1 = ss.getRange(['F3:F6'])
var r2 = ss.getRange(['H2'])
r1.clearContent();
r2.clearContent();
}
function onEdit (e){
if(e.range.getA1Notation() == "F2"){clearContent()
}
}
please help fix the script

Some options:
If you're running onEdit() from the console it won't work since it's supposed to be triggered only by modifications in the cells. Try changing F2
Could you try removing the brackets inside .getRange()? ss.getRange('F3:F6') and ss.getRange('H2')
Try only running clearContent() from the console and share what error it throws if any left.
Let us know!

Related

Google Apps Script: What is the correct way to check if I have access to a Google Spreadsheet by URL

I am currently writing a Google Apps Script inside a Google Sheet to read data from a list of spreadsheets (spreadsheet url is provided by the user). However, I cant seems to find a way to check if the url is valid or if user have access to the spreadsheet or not before calling SpreadsheetApp.openByUrl().
I have written the following code to "validate" the url:
for(int i = 0; i < urls.length; i++) {
let spreadsheet = null
try {
spreadsheet = SpreadsheetApp.openByUrl(urls[i]);
} catch (e) {
continue;
}
// Continue to do other stuff to read data from spreadsheet...
}
This however has an issue, it was able to catch the first few 'You do not have permission to access the requested document.' exception. But after a certain number of exception had occur, I would get a permenant error that cant be caught, stopping the script all together.
Is there a better way to do this?
Minimal reproducible example:
Create 3 google sheet using different google account
Using a different google account, create a google sheet and add the following code into Code.gs
function myFunction() {
// Put any 3 real spreadsheet url that you do not have access to
let urls = [
"https://docs.google.com/spreadsheets/d/1gOyEAz0amm4RghpE4B7f26okU3PG3vWZkrfiC-SBlbw/edit#gid=0",
"https://docs.google.com/spreadsheets/d/1Oia7ADu5BmYroUq1SLyDMHTJowrwSXOhCEyNO3nXmMA/edit#gid=0",
"https://docs.google.com/spreadsheets/d/1HE_IXURpBr_FJN--mwLo6k9gih07ZEtDGBqYSk6KgiA/edit#gid=0",
]
urls.forEach(url => {
try {
SpreadsheetApp.openByUrl(url)
} catch (e) {
console.log("Unable to open this spreadsheet")
}
})
}
function onOpen() {
SpreadsheetApp.getUi().createMenu("Test").addItem("myFunction", "myFunction").addToUi()
}
Run the function once in the apps script panel and authorize the application
Refresh this google sheet
Wait for the Custom Menus to show up and press "Menu" > "myFunction"
As you can see, the openByUrl() call is sitting inside the try catch block, however when you run the function through custom menu, you will still get "Error: You do not have permission to access the requested document.".
Executions Log:
From your question, I thought that your situation might be due to the specification or a bug of SpreadsheetApp.openByUrl. If my understanding is correct, in order to avoid this issue, how about putting the method for checking whether the file can be used before SpreadsheetApp? In your script, how about the following modification?
From :
SpreadsheetApp.openByUrl(url)
To:
var fileId = url.split("/")[5];
var file = DriveApp.getFileById(fileId);
spreadsheet = SpreadsheetApp.open(file);
In this modification, the file is retrieved with DriveApp.getFileById(fileId). When fileId cannot be used, an error occurs. But in this case, try-catch can be correctly worked. By this, the issue of SpreadsheetApp doesn't occur.

try/catch don't work with google script cell validation errors

I have a setValue() operation in a script in a cell with validation and if I use a value not in the list it throws an error. That's fine.
But my problem is that when I put a try/catch to avoid the error it doesn't work and I keep receiving the same error
To reproduce the problem:
create new sheet and set validation in B2 list of values a,b,c, reject others
function test() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
try { // don't work !!
ss.getRange('B2').setValue('x'); // value not in validation list
} catch(e) {Logger.log('error')}
}
Where is the problem???
I just tried this:
function changevaluenotinlist() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
sh.getRange('J2').setValue(5);
}
In my sheet J2 is in a validated range using a list equal to 1,2,3 and no error is returned in the software. So there should be no expectation to catch anything with a try/catch block. The error is only shown in the spreadsheet user interface. I guess that's because this is meant to be a user interface method provide the user with acceptable responses and it simply provides them with a visible indication of an error. I'd recommend that you get over it and move on.
Actually after selecting reject input I do get the error and your correct it does not get caught by a try catch block. Perhaps you should report it as an issue. Personally , I don't care.
You can use the flush() method after the set in order to get to the catch part.
function test() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
try { // don't work !!
ss.getRange('B2').setValue('x'); // a text value not in validation list (with numeric values donĀ“t fail)
SpreadsheetApp.flush()
} catch(e) {Logger.log('error')}
}

Google Sheets Script: Combining onEdit with openById("OtherSheetsId")

I am pretty bad at this but i did search around quite alot before posting here. I found some answers and I am now stuck at this part.
In short: We have 2 seperate google doc sheets. When a specific cell gets changed in Spreadsheet1, the script must change a specific cell's value in Spreadsheet2.
function onEdit(e) {
var mainsheet = SpreadsheetApp.getActive().getSheetByName('Main');
var changeit = sheet.getRange("A1").getValue();
var offsheet = SpreadsheetApp.openById("spreadsheet2s id").getSheetByName('Echo').getRange("A1");
if (changeit == 'true'){
offsheet.setValue('true');
}
It basically does not work, and in scripts, when I go to Run -> Executions Transcript it tells me Execution failed: You do not have permission to call SpreadsheetApp.openById.
When I try this for the same sheet it works fine.
It seems that an installable trigger would do the trick, but i have not been able to find anything on what exactly to do here, as in how to apply an installable trigger.
It is said by google info that this will allow a function to change info on another sheet. How would we make this only apply to the onEdit(e) function listed above?
And the biggest question is, how do we make this work / tie it all together? What I have done is just pasted this underneath (as if it was its own function).
I have played around with it in various ways (such as trying to add the openByID info in this and afew other silly things) and I think I missing something simple here.
function createSpreadsheetEditTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger('onEdit')
.forSpreadsheet(ss)
.onEdit()
.create();
}
Thank you in advance for your help.
Try this:
function ss1OnEdit(e){
if(e.range.getSheet().getName()!='Main') return;
SpreadsheetApp.openById("ss2id").getSheetByName("Echo").getRange(e.range.getA1Notation()).setValue(e.value);
}
//You can run this function all you want it will not create more than one trigger. But you must run it once to setup the first trigger.
function createSS1OnEditTrigger() {
var ss=SpreadsheetApp.getActive();
var trgs=ScriptApp.getProjectTriggers();
var found=false;
for(var i=0;i<trgs.length;i++) {
if(trgs[i].getHandlerFunction()=="ss1OnEdit") {
return;
}
}
if(!found) {
ScriptApp.newTrigger("ss1OnEdit").forSpreadsheet(ss.getId()).onEdit().create();
}
}

GAS - Authentication w/ UrlFetchApp - Form to Spreadsheet

I am testing the functionality of UrlFetchApp and passing data from a Form and its Spreadsheet. I know it's possible to do this another way, however I am testing the functionality of UrlFetchApp (first time using it) within google scripts themselves, and want to get it to work with this method.
Here's the scenario I got, add a bound script to a Form App as so:
function makeRequest()
{
var webAppUrl = "https://script.google.com/macros/s/WebAppID/exec";
var auth = ScriptApp.getOAuthToken();
var header = { 'Authorization': 'Bearer ' + auth };
var options = { 'method':'post', 'headers':header };
var resp = UrlFetchApp.fetch(webAppUrl, options);
Logger.log(resp);
}
Add a bound script to the attached spreadsheet:
function doPost()
{
var ss = SpreadsheetApp.openById('ssID');
var name = ss.getName();
return ContentService.createTextOutput(name);
}
And then publish this second script attached to the sheet as a web app with only myself to have access.
Currently the above code does not work. The following error appears on the Form side of the script:
Request failed for
https://script.google.com/macros/s/WebAppID/exec
returned code 401. Truncated server response:
Unauthorized Unauthorized Error 401
(use muteHttpExceptions option to examine full response) (line
12, file "Code")
Fails on the UrlFetchApp line of code.
However, if I remove the header option, then publish the web app for public use, this works just fine. Obviously this is not wanted.
What am I missing regarding authentication between scripts that I own?
Side Notes:
Anyone know why SpreadsheetApp.getActiveSheet() doesn't work when run in this fashion? That script is directly bound to a google sheet, so kind of odd.
Ok, found the answer to my own question. It was quite simple really. Needed to add the following scope to my project for accessing a spreadsheet:
https://www.googleapis.com/auth/drive
The easiest way I found to do this is to add a simple function like this and call it:
function authorizeDrive()
{
var forScope = DriveApp.getRootFolder();
}
Doesn't need to return or do anything, just call any method from the DriveApp. Once run, it'll then popup with a dialogue for authorization. Don't even need to call this every time you do your main method calls. Don't even need to leave it coded in the script either. I wonder if there is way to just simple add the scope you need to a project from a properties window (I didn't find any). Or perhaps a way to pass a parameter along with UrlFetchApp regarding what scope need authorized.
Buy anyhow this still wasn't too bad.
Regarding my side note, I still haven't found a reason as to why SpeadsheetApp.getActiveSheet() returns null or undefined. I have to open by ID or URL, which is a pain. Especially since this is a container bound script. Also noticed that Logger.log() doesn't actually add anything to the Logger when run in this manner. If anyone could still shed some light on either of these, that would be great.
You need to get the 'Spreadsheet' object first.
SpeadsheetApp.getActive().getActiveSheet()
However, if you are creating an add-on menu you can use 'SpreadsheetApp.getActiveSheet()'
function myFunction() {
var lastRow = SpreadsheetApp.getActiveSheet().getLastRow();
var range = SpreadsheetApp.getActiveSheet().getRange(lastRow, 1, 1, 26);
SpreadsheetApp.setActiveRange(range);
}
function onOpen(e) {
SpreadsheetApp.getUi().createAddonMenu()
.addItem('showLastRow', 'myFunction')
.addToUi();
}

TypeError: Cannot call method "show" of null

I see some sample code from other site and i see this but when i paste and run it's have an error "TypeError: Cannot call method "show" of null. (line 5, file "
function hello() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle('title Dude');
app.add(app.createLabel('Hello World'));
ss.show(app);
}
Can some help me with this?
This script must be launch from a script within a spreadsheet and not a standalone script window. But anyway the UiApp service is deprecated since end of 2014 and you have to use HTML service to build user interface.
This code will no longer work.
Could it be that you have no active spreadsheet ?
SpreadsheetApp.getActiveSpreadsheet()
So it's return null