Run Google Script Through Last Spreadsheet Row Only? - javascript

I'm running an email script which works fine, but I only want it to run through the last row with data in it. I don't need it or want it to run if there is no data obviously. How do I reflect that in the example script below?
For example, say there are only 3 rows of data in my sheet. I only need the script to run for those 3 rows but the code will run for 20 rows. The number of entries to process will vary by the day so I can't just set it at a set number.
Basically I'm looking to replace:
var numRows =20;// Number of rows to process
with some iteration of .getlastrow...I think?
Sample script for reference:
function sendEmails() {
var sheet =SpreadsheetApp.getActiveSheet();
var startRow =2;// First row of data to process
var numRows =20;// Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow,1, numRows,2)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for(i in data){
var row = data[i];
var emailAddress = row[0];// First column
var message = row[1];// Second column
var subject ="Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
}
}
Thanks for your help!

You can use the getLastRow() method to get the index of the last populated row in the sheet. Or use getDataRange().getValues and it will only get the rows that have data.
function sendEmails(){
var sheet = SpreadsheetApp.getActiveSheet();
var startRow =2;// First row of data to process
var data = sheet.getDataRange().getValues();
for(var i=startRow; i<data.length; i++){
var row = data[i];
var emailAddress = row[0];// First column
var message = row[1];// Second column
var subject ="Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
}
}

Related

How to copy and set a row of data into another sheet if a string condition is met in a column

I've been trying to create a Submit sheet that has 42 rows. They have a border around it indicating where I type my data in. My goal is once Submit is typed in at the end of the row it'll paste that row of data into the bottom of my Database sheet
Here is the code ive been writing and having problems with. Sorry if it looks whacky I'm rookie at this
function submit1(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet");
var range = sheet.getDataRange();
var colVal = "Submit";
var colToSearch = 19;
var dataRangeVals = range.getValues();
for(var i = dataRangeVals.length; i <= 173; i++){
if([i][colToSearch] === colVal){
var sourceVal = sheet.getRow(i+[colToSearch]).getValues();
Logger.log(sourceVal);
var targetSheet = ss.getSheetByName("DataBase");
var lastRow = targetSheet.getLastRow();
targetSheet.getRange(lastRow + 1,1,1,18).setValues(sourceVal);
};
};
};
the var dataRangeVals works and gets all the values of my submit sheet, but when I iterate through it and log sourceVal to check if it grabbed the row of data when I typed Submit into Column T
No values show in the execution log which is probably why nothing gets pasted into my DataBase sheet but it still shows execution complete without any errors which is confusing me . The problem is I don't understand why that's happening.
If you guys could help me out and take a look at it i'd greatly appreciate it.
Here is the link if you'd like it.
Stock Database updated link
Issues:
for(var i = dataRangeVals.length; i <= 173; i++){ will start at 131 and no data will be captured. Instead, replace it with for(var i = 0; i < dataRangeVals.length; i++){.
[i][colToSearch] wont return anything. To read the element of an array it should be dataRangeVals[i][colToSearch].
I tried to print the column T of your sheet and the Submit text has extra space in it. if([i][colToSearch] === colVal){ won't work because Submit is not equal to Submit . Instead use String.match().
sheet.getRow(i+[colToSearch]) wont work because Class Sheet has no getRow() method. Replace getRow() with getRange(row, column, numRows, numColumns)
Code:
function submit1(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet");
var range = sheet.getDataRange();
var colVal = "Submit";
var colToSearch = 19;
var dataRangeVals = range.getValues();
for(var i = 0; i < dataRangeVals.length; i++){
if(dataRangeVals[i][colToSearch].toString().match(colVal)){
var sourceVal = sheet.getRange(i+1, 1, 1, 19).getValues();
var targetSheet = ss.getSheetByName("DataBase");
var lastRow = targetSheet.getLastRow();
sourceVal[0].splice(0,1)//remove the empty first element of subarray
targetSheet.getRange(lastRow + 1,1,1,18).setValues(sourceVal);
};
};
};
Output:
I tested your code and found that on your IF condition if([i][colToSearch] === colVal), the [i][colToSearch] has a null or undefined value as seen here on the execution log result. Thus, your IF statement automatically ends the execution of your code and no values are shown.
I did some tweaks on your code to be able to proceed on the IF statement (to find if the last row matches the word "Submit") then copy the last row data from "Sheet" to the "DataBase" sheet's last row.
Please refer to my sample code here: Updated
function submit1(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet");
var range = sheet.getDataRange();
var targetSheet = ss.getSheetByName("DataBase");
var lastRow = targetSheet.getLastRow()+1;
var colVal = "Submit";
var colToSearch = 20;
var dataRangeVals = range.getValues();
for(var i = 1; i <= dataRangeVals.length; i++){//Loop to check column 20 with "Submit" value
if(sheet.getRange(i,colToSearch).getValue().valueOf(colVal)){//Check each rows on column 20 to find ones that has "Submit" value
for(var x = 2; x<=colToSearch-1; x++){//When a row has "Submit" value, it will get all row data and copies it to "DataBase" sheet
var sourceVal = sheet.getRange(i,x).getValues();
targetSheet.getRange(lastRow,x-1).setValues(sourceVal);
}
lastRow = targetSheet.getLastRow()+1;//Refreshes the new last row on "DataBase" sheet
Logger.log("Done copying row data on \"Sheet\" Row #" + i + " to \"DataBase\"");
}else{
//Do nothing
}
}
}
After running the code, you will be able to see all of the data from the row on "Sheet", copied and added on every last row of the "Database" Sheet. You Should this sample execution log result once it is successful.
Updated Result
Here's my test spreadsheet, based on your spreadsheet design:
Here's the result on DataBase sheet:

How to access 2nd tab on Google Sheets using App Script/JavaScript?

I want to access simply the 2nd tab to get email and name values to be used to send automated emails. Currently, the code is using the first tab. Additionally, how do I specify that it should take only rows (on the second tab) which have values instead of taking the entire column with many blanks which then throw errors?
function sendemail() {
var spreadSheet = SpreadsheetApp.getActiveSheet();
var dataRange = spreadSheet.getDataRange();
var data = dataRange.getValues();
for (var i = 1; i < data.length; i++) {
(function(val) {
var row = data[i];
var emailAddress = row[1]; //position of email header — 1
var message = 'Hi There!';
var subject = 'Test';
MailApp.sendEmail(emailAddress, subject, message);
})(i);
}
}
To get the second sheet / tab in a Spreadsheet you can use the getSheets method and take the second element of the returned list of Sheets:
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var secondSheet = sheets[1];
To retrieve only populated rows use the getDataRange method to retrieve the Range in which data is present, and retrive the values.
var range = secondSheet.getDataRange();
var values = range.getValues();

Sending email when a dropdown item is selected through a Sheet script

I am trying to send an email to the address supplied in column A when the Status drop down in column H has been set to "Completed". Here is what I have so far:
function onOpen() {
sendemail();
}
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = 'EMAIL_SENT';
var COMPLETED = 'Completed';
/**
* Sends non-duplicate emails with data from the current spreadsheet.
*/
function sendemail() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 400; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 3); //grabbing ranges
of values to get
var data = dataRange.getValues(); //getting values
var status = sheet.getRange(startRow, 8, numRows, 1); //grabbing ranges of
//values to get
var data_status = status.getValues(); //getting values
//logic: if a field is populated and both Column C isn't populated, and
//Status is Completed, populate corresponding row in column C and send email.
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = "";
var emailSent = row[2]; // Third column
if (emailSent != EMAIL_SENT && data_status == COMPLETED) { // Prevents
sending duplicates
var subject = 'Sending emails from a Spreadsheet';
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is
interrupted
SpreadsheetApp.flush();
}
}
}
This code is heavily influenced from google and I am able to grab all of the info from column H, I'm just unsure of what I am doing wrong. The issue is that it's not working. If I take out the and section of the if statement, it will work just fine, and If I debug the code I can see the array of values given to me from column H. For each "completed" value I need it to send the email, however I don't want the email to be sent if the status is set to completed and the Column C has the value EMAIL_SENT Thank you for your help
I think that your script is almost complete. I think that the script works by modifying one part. So how about this modification?
Modification point :
In your script, data_status is 2 dimensional array. And when the value of each row is compared to "COMPLETED", whole array is comparing.
In order to reflect above to your script, please modify as follows.
From :
if (emailSent != EMAIL_SENT && data_status == COMPLETED) {
To :
if (emailSent != EMAIL_SENT && data_status[i][0] == COMPLETED) {
If this didn't work, please tell me. I would like to modify it.

Google Sheets: Those rows are out of bounds, can't figure out why

I've been piecing together a script to delete empty rows from a specific tab in a series of spreadsheets. It works up until the point it has to delete the rows, throwing a Those rows are out of bounds error. I followed this technique to delete the rows, which seems to have good results for others, so I'm having trouble figuring out why this isn't working.
I thought maybe it was that I was exceeding the number of deletable rows by 1, but tested that, and it didn't make a difference.
Any ideas? Thanks for the input!
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(2,3,17);
var values = range.getValues();
for (var row in values){
for (var col in values[row]) {
var theUrl = values[row][col];
var openTheUrl = SpreadsheetApp.openByUrl(theUrl);
Logger.log(openTheUrl.getName());
var currentSheet = openTheUrl.getSheetByName("Aggregate");
Logger.log(currentSheet.getName());
var maxRows = currentSheet.getMaxRows();
var lastRow = currentSheet.getLastRow();
var deleteRows = maxRows-lastRow;
if (maxRows-lastRow != 0){
sheet.deleteRows(lastRow+1, deleteRows);
}
}
}
}
In your script, I can understand as follows.
You want to delete rows using maxRows and lastRow retrieved from currentSheet opened by theUrl.
The rows that you want delete is in currentSheet.
If my understanding is correct, how about this modification?
From :
sheet.deleteRows(lastRow+1, deleteRows);
To :
currentSheet.deleteRows(lastRow+1, deleteRows);
If I misunderstand your question, I'm sorry.

I want to hide Columns on each sheet according to a value in Cells in row 1

I get an error every time I try this here is what I am using. I get this error:
TypeError: Cannot find function hideColumns in object Sheet,Sheet,Sheet,Sheet,Sheet."
I am not very familiar with scripts and cant seem to get this to work.
function Hide() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// look at all sheets
var sheet = ss.getSheets();
// get data
var data = ss.getDataRange();
// get number of columns
var lastCol = data.getLastColumn()+1;
Logger.log(lastCol);
// itterate through columns
for(var i=1; i<lastCol; i++) {
if(data.getCell(1, i).getValue()[0] == '*') {
sheet.hideColumns(i);
}
}
}
Could some one help me?
I am assuming, you are using this reference. I guess, you want to do the following:
Iterate all the columns in the data range.
If the value of the first row of column equals * then hide that column.
I am not familiar with Google Apps Services, but I think your code should look like this:
function Hide() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// look at all sheets
//var sheet = ss.getSheets();
// get data
var data = ss.getDataRange();
//get the sheet this range belongs to.
var sheet = data.getSheet();
// get number of columns
var lastCol = data.getLastColumn()+1;
Logger.log(lastCol);
// itterate through columns
for(var i=1; i<lastCol; i++) {
if(data.getCell(1, i).getValue()[0] == '*') {
sheet.hideColumns(i);
}
}
}
Since .getSheets return an Array of Sheet objects you can not call that function.

Categories