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

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.

Related

How to clear certain cells on opening a spreadsheet

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

How do I get Snipe-IT API to retrieve data using a Google App Script and populate it on a Google Sheet?

I am attempting to create a visualization of the data we have on Snipe-IT Asset Management on Google Data Studio. To do so, I am creating a Google Sheets spreadsheet with an App Script extension that will communicate with the Snipe-IT API, retrieve the data, and populate it on the Google Sheet. So far, I've been able to get the API to populate some of our data on the terminal but not on the spreadsheet itself.
I wrote a simple script that should list out the assets assigned to one particular user, for testing purposes. Again, the script works fine, it populates the data I need on the terminal but not on the Google Sheet. Here is my exact code (excluding SETUP section details):
//SETUP
serverURL = 'SERVER-URL'; (ignore)
apiKey = 'API-KEY' (ignore)
function onOpen(e) {
createCommandsMenu();
}
function createCommandsMenu() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Run Script')
.addItem('Get Assets By Department', 'runGetAssetsByDepartment')
.addToUi();
}
function testGetAssetsByUser(){
getAssetsByUser("1745")
}
//Get assets for a user by id
//Returns a list of assets by id
function getAssetsByUser(userID) {
var url = serverURL + 'api/v1/users/' + userID + '/assets';
var headers = {
"Authorization" : "Bearer " + apiKey
};
var options = {
"method" : "GET",
"contentType" : "application/json",
"headers" : headers
};
var response = JSON.parse(UrlFetchApp.fetch(url, options));
var rows = response.rows;
var assets = []
for (var i=0; i<rows.length; i++) {
var row = rows[i];
if (row.category.name == "Laptop" || row.category.name == "Desktop" || row.category.name == "2-in-1") {
var asset = row.id
assets.push(asset)
}
}
return assets
}
console.log(getAssetsByUser(1745));
There are several ways to write values into an spreadsheet
The basics
Grab the spreadsheet
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
This works in bounded projects and add-ons
Grab the destination sheet
var sheet = spreadsheet.getSheetByName('put here the sheet name');
You might use SpreadsheetApp.getActiveSheet() if your spreadsheet has only one sheet, but for functions being called from a custom menu this one is risky.
Write values into the destination sheet
Preparation: Make a 2D Array
var output = assets.map(v => [v]);
Do: Write values into the destination sheet
sheet.getRange(1,1,output.length, 1).setValues(output);
Resources
https://developers.google.com/apps-script/guides/sheets

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!

Google sheets scripts function UrlFetchApp.fetch does not run from .onEdit(e) but works from editor

I have created a google sheet with a lot of info for a beach volleyball cup and I want to call an API I have created when a checkbox is checked in this sheet.
function onEdit(e){
const ui = SpreadsheetApp.getUi();
const spreadsheets = SpreadsheetApp.getActive();
const configSheet = spreadsheets.getSheetByName("Config")
var tourneyId = String(configSheet.getRange(2,4).getValue())
var tourneyTitle = String(configSheet.getRange(2,5).getValue())
var sheet = spreadsheets.getActiveSheet()
if (sheet.getName() == "LiveScore"){
var actRng = sheet.getActiveRange();
var editColumn = actRng.getColumn();
var rowIndex = actRng.getRowIndex();
actRng = actRng.getCell(1, 1);
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
if(editColumn == 7 && rowIndex != 1){
onStartBroadcastClicked(actRng, ui, sheet, rowIndex, editColumn, tourneyTitle);
}
}
}
There is never any problems with this part as I see it. But when i get into the function onStartBroadcastClicked:
function onStartBroadcastClicked(actRng, ui, sheet, rowIndex, editColumn, tourneyTitle){
var homeTeam = String(sheet.getRange(rowIndex, 14).getValue());
... // more setting variables
var endTime = new Date(startTime.getTime() + MILLIS_PER_MATCH);
if(actRng.isChecked()){
var response = ui.alert("You are about to start a new broadcast. Are you sure?" +
"\n Title: " + title, ui.ButtonSet.YES_NO);
if (response == ui.Button.YES) {
var httpRequest = "https://someUrl";
var options =
{
'method':'POST',
'contentType': 'application/json',
'payload' : JSON.stringify({
"title" : title,
... // setting all variables
"description" : description
}),
'muteHttpExceptions' : true,
'headers' : {
"Authorization": "Basic " + Utilities.base64Encode(USERNAME + ":" + PASSWORD)
}
};
ui.alert("Waiting.......")
var result = UrlFetchApp.fetch(httpRequest, options);
ui.alert(result.getContentText())
The issue is that it always gets to the line ui.alert("Waiting......."), but when triggered from the checkbox, it never succeeds the http POST request. If I click play inside the editor, it succeeds and I got the response in the alertbox.
Could it be some timeout or some autosave issues? Does anyone have any idea if where to keep looking? I've been stuck here for some time now and I would be really happy if anyone can point me to the correct direction.
The modification point of your issue is to use the installable trigger of OnEdit event. When the methods which are required to authorize used at the simple trigger, the error occurs. This situation makes us think that it seems the script doesn't work.
In order to avoid this error, please use the installable triggers of OnEdit event trigger.
As an important point, before you install the trigger, please rename the function name of onEdit() to other name. And install the renamed function name as the OnEdit event trigger. By this, the duplicate run of onEdit() can be prevented. If onEdit() function is installed as the installable trigger, when a cell is edited, the function is run 2 times. Ref.
By above settings, when the cell is edited, UrlFetchApp.fetch() works.
References:
Simple Triggers
Installable Triggers
Asynchronous Processing using Event Triggers
I was able to get a script to work with a trigger if I created the script from script.google.com and call the Google Sheet and tab from the script. I'm manually entered in my API calls per cell within a specified Row:
function fetchUrls() {
var spreadsheetId = "ENTER GOOGLE SHEET ID";
var spreadsheet = SpreadsheetApp.openById(spreadsheetId);
var sheet = spreadsheet.getSheetByName("ENTER SHEET NAME");
var range = sheet.getRange("ENTER RANGE OR FULL COLUMN"); // specify the range of cells in column B
var urls = range.getValues(); // get the values of the cells and store them
in an array
var cache = CacheService.getScriptCache();
for (var i = 0; i < urls.length; i++) {
if(urls[i][0] != "") { // check if the current cell is not empty
var url = urls[i][0];
var result = cache.get(url);
if(!result) {
var response = UrlFetchApp.fetch(url);
result = response.getContentText();
cache.put(url, result, 21600);
}
sheet.getRange(i+1,3).setValue(result); // set the value of the current cell to the result of the API call in column C
}
}
}

Email notification: TypeError: Cannot find function getColumn in object 1

I'm new to javascript and I'm trying to write this function that will be used in google sheet so that whenever a value is changed in a specific cell, it will send an email notification to say that cell has been changed. The problem lies is when I used this code in a google sheet there is an error:
"TypeError: Cannot find function getColumn in object 1"
Im not sure what is causing this and I have attempted to look at other peoples problems similar to this but I just dont understand why it is doing this.
Code:
function onEdit(e)
{
var range = e.range;
if (e.getColumn() == 11)
{
var previous = range.offset(0, -1);
var next = range.offset(0, 1);
var emailAddress = 'myemail#gmail.com';
var message = 'Data Changed';
var subject = 'Test Awareness Mail';
GmailApp.sendEmail(emailAddress, subject, message);
}
}

Categories