How to clear certain cells on opening a spreadsheet - javascript

I am trying to get my Google Sheet to clear certain cells on opening it. I've never added Apps Script to any sheet, so step by sp instructions will be greatly appreciated.
I'm getting an error when trying to deploy the script below.
function onOpen() {
function clearRange() {
// replace 'Sheet2' with your actual sheet name
// replace '1AsVArsUf5DaIXqzyPEokCRkPVglxSPW4NgWg_PVtLhA/edit#gid=1395849459' with your actual sheet ID
var sheetActive = SpreadsheetApp.openById("1AsVArsUf5DaIXqzyPEokCRkPVglxSPW4NgWg_PVtLhA/edit#gid=1395849459").getSheetByName("Sheet2");
sheetActive.getRange('G83,G143,E143,G210,G221').clearContent();
}
}

Clear Ranges:
function onOpen() {
clearRange()
}
function clearRange() {
const ss = SpreadsheetApp.openById("1AsVArsUf5DaIXqzyPEokCRkPVglxSPW4NgWg_PVtLhA/edit#gid=1395849459");
const sh = ss.getSheetByName("Sheet2");
const rgl = sh.getRangeList(['G83','G143','E143','G210','G221']).getRanges().forEach(r => r.clearContent())
}
You probably need an installable trigger because you are using openById()
Sheet.getRangeList

Related

TypeError: Cannot read properties of undefined (reading 'range')

I want to setup a simple file approval workflow in a google sheet:
On column A I will have the link of a file
On columns B, C, D I will have checkboxes for the team.
When all 3 checkboxes are checked, the file from col A will be moved to a specific Google Drive folder.
I imported this script as a macro but I get this error:
TypeError: Cannot read properties of undefined (reading 'range')
In the final version the folder ID is the correct one
I have added from the services Google Drive and Google Sheets
function onChange(e) {
if (e.range) {
var checkboxB = e.range.getSheet().getRange(e.range.getRowIndex(), 2).getValue();
var checkboxC = e.range.getSheet().getRange(e.range.getRowIndex(), 3).getValue();
var checkboxD = e.range.getSheet().getRange(e.range.getRowIndex(), 4).getValue();
if (checkboxB && checkboxC && checkboxD) {
var fileLink = e.range.getSheet().getRange(e.range.getRowIndex(), 1).getValue();
var folderId = 'THIS_IS_THE_FOLDER_ID';
var file = DriveApp.getFileByUrl(fileLink);
file.getParents().next().removeFile(file);
DriveApp.getFolderById(folderId).addFile(file);
Logger.log('File ' + file.getName() + ' was moved to folder ' + folderId);
}
}
}
//onEdit trigger google sheet
function onEdit(e) {
onChange(e);
}
From the question:
I imported this script as a macro
The onChange(e) function you quote is designed to run through an installable trigger.
The onEdit(e) function you quote is designed to run through a simple trigger.
These triggers fire automatically when you manually edit the spreadsheet. In that context, the event object e is properly populated.
Neither function will work if you run them as a macro. If you run them as macro, the event parameter e is not populated, causing the error you mention. The same happens if run the code through the Run button in the script editor.
In the final version the folder ID is the correct one
The onEdit(e) function, and any code you run through it, cannot access the DriveApp class because simple triggers cannot run methods that require authorization.
I have added from the services Google Drive and Google Sheets
There is no need to do that, since you are not using the Drive or Sheets advanced services. You are using the DriveApp and SpreadsheetApp classes which are not the same thing as those advanced services.
What you need is an installable "on edit" trigger, like this:
function onInstallableEditTrigger(e) {
if (!e) {
throw new Error('Install a trigger to run this function.');
}
if (!e.range
|| e.range.columnStart < 2
|| e.range.columnStart > 4) {
return;
}
const sheet = e.range.getSheet();
const checkboxes = sheet.getRange(e.range.rowStart, 2, 1, 3).getValues();
if (checkboxes.some(value => value !== true)) {
return;
}
const fileLink = sheet.getRange(e.range.rowStart, 1).getValue();
// ...proceed to move file
}
Create an installable "on edit" trigger to run the above function. You should delete your existing installable "on change" trigger and the onEdit(e) function.

Google Docs script giving unspecified error - Unsure of cause

I'm new to Google Docs scripting, and am following this tutorial in order to create Google docs from a template and a Google sheet. I've written everything as the tutorial specifies - here's the entirety of my code:
function onOpen() {
const menu = SpreadsheetApp.getUi().createMenu('Create Review Forms');
menu.addItem('Create Review Forms', 'createNewGoogleDocs');
menu.addToUi();
}
function createNewGoogleDocs() {
const googleDocTemplate = DriveApp.getFileById('1JqwXS_yOo_v2CV5akOf26tQnj-AdB3cvrVmxTn10lZI');
const destinationFolder = DriveApp.getFolderById('1ZFaHXonRQZ-2S5YGj5vCRu_r23vWoVod');
const rows = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1').getDataRange().getValues();
Logger.log(rows)
rows.forEach(function(row, index){
if (index === 0) return;
if (row[6]) return;
const copy = googleDocTemplate.makeCopy(`${row[1]} ${row[2]} application`, destinationFolder);
const doc = DocumentApp.openById(copy.getId());
const body = doc.getBody();
body.replaceText('{{Cand Number}}', row[0]);
body.replaceText('{{Resume}}', row[1]);
body.replaceText('{{Essay 1}}', row[2]);
body.replaceText('{{Essay 2}}', row[3]);
body.replaceText('{{Essay 3}}', row[4]);
doc.saveAndClose();
sheet.getDataRange(index + 1, 6).setValue(doc.getUrl());
})
}
It works insofar as a menu option is created as specified in the onOpen function. However, every time I try to run or debug the whole thing, I get this "Unknown error" in the execution log:
This started even after I wrote the first couple of lines in the lower function, but even when I comment them out the Unknown Error persists. I'd appreciate any help anyone can offer!

How to set the newly created sheet as the active sheet? Google sheets

Am having a problem that I have to run each script alone due to not being able to switch to the newly created sheet generated by the function copyWithProtections, so when the next function ClearValueAftercreatingnewsheet runs, it runs on the active sheet not the newly generated one, is there a way to to have the newly created sheet as the active one?
/* CAUTION: COPY WITH PROTECTION SHOULD BE RUNNED FIRST THEN CLEARVALUEAFTERCREATING NEW SHEET AFTER MAKING SURE THAT YOU MANUALLY CHANGED THE ACTIVE SHEET TO THE NEW SHEET WITH THE NUMBER */
//Copies with protection
function copyWithProtections(){
const sh = SpreadsheetApp.getActiveSpreadsheet();
const ss = sh.getSheetByName("Mar22");
const prot = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE)
let nSheet = ss.copyTo(sh).setName(sh.getNumSheets()-1);
let p;
for (let i in prot){
p = nSheet.getRange(prot[i].getRange().getA1Notation()).protect();
p.removeEditors(p.getEditors());
if (p.canDomainEdit()) {
p.setDomainEdit(false);
}
}
}
//Clears Values of new sheets
function ClearValueAftercreatingnewsheet() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A2:P144').activate().clear({contentsOnly: true});
spreadsheet.getRange('Z5').activate();
spreadsheet.getCurrentCell().setValue('');
spreadsheet.getRange('Z8').activate();
spreadsheet.getCurrentCell().setValue('');
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('A2:Q270').activate();
spreadsheet.getActiveRangeList().setBackground('#deeaf6');
spreadsheet.getRange('A2:R270').activate();
spreadsheet.getActiveRangeList().setBorder(true, true, true, true, true, true, '#000000', SpreadsheetApp.BorderStyle.SOLID);
};
You can set the active sheet from the sheet name.
By making your script in one single function, you can use the newly created output sheet nSheet and get it's name using getSheetName(). You can then reference it on the clear values part. Try the following code instead:
function copyAndClear() {
//Copies with protection
const sh = SpreadsheetApp.getActiveSpreadsheet();
const ss = sh.getSheetByName("Mar22");
const prot = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE)
let nSheet = ss.copyTo(sh).setName(sh.getNumSheets() - 1);
let p;
for (let i in prot) {
p = nSheet.getRange(prot[i].getRange().getA1Notation()).protect();
p.removeEditors(p.getEditors());
if (p.canDomainEdit()) {
p.setDomainEdit(false);
}
}
//Set the newly created sheet name in a variable to be used for reference
var nSheetName = nSheet.getSheetName();
//Clears Values of new sheets
var spreadsheet = sh.getSheetByName(nSheetName);
spreadsheet.getRange('A2:P144').activate().clear({contentsOnly: true});
spreadsheet.getRange('Z5').setValue('');
spreadsheet.getRange('Z8').setValue('');
spreadsheet.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});
spreadsheet.getRange('A2:Q270').setBackground('#deeaf6');
spreadsheet.getRange('A2:R270').setBorder(true, true, true, true, true, true, '#000000', SpreadsheetApp.BorderStyle.SOLID);
};
I have also simplified your code to avoid redundancy and make the run time shorter since based on your code there's no need for the .activate() if you can just set it directly in one line.
Let me know if this works!
You can also set the active sheet by ID but the code will be much longer.
Here's the reference for setting active sheet: https://spreadsheet.dev/activate-sheet-in-google-sheets-using-google-apps-script
EDIT: I have kept the .activate() on the first line
spreadsheet.getRange('A2:P144').activate().clear({contentsOnly: true});
as for some reason if I set it directly as
spreadsheet.getRange('A2:P144').clear({contentsOnly: true});
without the .activate() it is also clearing the original sheet.

Extend seach range for all sheets

I am using this script and an input form to search a Google spreadsheet, this script has a range of one sheet,i.e. Data , but I need to extend my range to all sheets in the same spreadsheet, any ideas?
function doGet(e) {
return HtmlService.createTemplateFromFile("Index").evaluate()
.setTitle("WebApp: Search By Password")
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
/* PROCESS FORM */
function processForm(formObject) {
var concat = formObject.searchtext + formObject.searchtext2;
var result = "";
if (concat) {//Execute if form passes search text
result = search(concat);
}
return result;
}
//SEARCH FOR MATCHED CONTENTS ;
function search(searchtext) {
var spreadsheetId = ' '; //** CHANGE !!!!
var sheetName = "Data"
var range = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName).getDataRange();
var data = range.getValues();
var ar = [];
data.forEach(function (f) {
if (~[f[8]].indexOf(searchtext)) {
ar.push([f[2], f[3], f[4], f[5], f[6], f[7]]);
}
});
return ar;
}
I believe your goal is as follows.
You want to search for a text from all sheets of a Google Spreadsheet.
You want to achieve this by modifying the script in your question.
In this case, I would like to propose modifying the function search as follows.
Modified script:
function search(searchtext) {
return SpreadsheetApp
.getActiveSpreadsheet()
.getSheets()
.flatMap(s =>
s
.getDataRange()
.getValues()
.filter(r => r[8] && r[8].includes(searchtext))
.map(([,,c,d,e,f,g,h]) => [c,d,e,f,g,h])
);
}
Note:
When you modified the Google Apps Script, please modify the deployment as a new version. By this, the modified script is reflected in Web Apps. Please be careful about this.
You can see the detail of this in the report of "Redeploying Web Apps without Changing URL of Web Apps for new IDE".
References:
getSheets()
filter()
map()

How to update PivotTable with Google App Script?

I need help to update a pivotTable with google app script. Is there a good way to do it?
The pivotTable will create with the following function:
function pivotTableTest() {
// Ask for the source spreadsheet name
// Has to enter with range!
var ui = SpreadsheetApp.getUi();
var sourceSpreadsheet = ui.prompt("Enter the sheet name with range:");
Logger.log(sourceSpreadsheet.getResponseText());
Logger.log(sourceSpreadsheet.getSelectedButton());
// Create PivotTable
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceData = spreadsheet.getRange(sourceSpreadsheet.getResponseText());
var pivotTable = spreadsheet.getRange('B3').createPivotTable(sourceData);
// Add Rows
var pivotGroup = pivotTable.addRowGroup(3);
Now I need a function to add Values to the pivotTable:
function addValue() {
//???????????????????????????????????????
//pivotValue = pivotTable.addPivotValue(31, SpreadsheetApp.PivotTableSummarizeFunction.SUM);
}
But I don't know how to write the function, because the only way to do this was create a new PivotTable..
Thanks for your help!

Categories