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();
Related
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:
The challenge has been getting cell values from the document header together with a range underneath this header to Sheet2, having it as a table, so that later, I can filter, update and delete records via scripts.
So far, I got the below code copying what's within the range underneath the header:
function copyrange() {
var sourceSheet = 'NewItem';
var destinationSheet = 'DW';
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sourceSheet);
var LastRowSource = sheet.getLastRow();
var LastColumnSource = sheet.getLastColumn();
var values = sheet.getRange(11,1,LastRowSource,LastColumnSource).getValues();
var csh = ss.getSheetByName(destinationSheet);
var data = [];
var j =[];
//var itemheader = [sheet.getRange("C4:4").getValues(),sheet.getRange("A3:3").getValues(),sheet.getRange("i3:3").getValues(),sheet.getRange("i4:4").getValues(),sheet.getRange("c5:5").getValues(),sheet.getRange("e5:e").getValues(),sheet.getRange("i5:5").getValues(),
// sheet.getRange("C7:7").getValues(),sheet.getRange("c8:8").getValues(),sheet.getRange("c9:9").getValues(),sheet.getRange("e7:7").getValues(),sheet.getRange("e8:8").getValues(),sheet.getRange("i7:7").getValues(),sheet.getRange("i8:8").getValues(),
// sheet.getRange("e9:9").getValues()];
for (var i = 1; i < values.length; i++) {
if ( values[i][0] != '') {
data.push(values[i]);
//sheet.deleteRow(i+1)
}
}
//Copy data array to destination sheet
csh.getRange(csh.getLastRow()+1,17,data.length,data[0].length).setValues(data);
Now, getting different cell values from the header into a row and copying it to Sheet2 as many times/rows as there is in the range copied by the above script seems impossible to me.
Here is a link to a practical example:
https://docs.google.com/spreadsheets/d/1GlD_VIOFHj7PGfCCnfVZqdZbE22aVoUw91BSCZecsRc/edit?usp=sharing
Thanks a lot for your help. Believe me, I've hit my head against the wall enough with this one before I turn to you guys!
I have a google form with a dropdown (see below)
I have a column on a google sheet that gets updated everyday.
Is there any way that I can automatically link the names from the google sheet to the google form dropdown Question 1 such that each time the sheet gets updated with an additional name - the google form automatically gets updated with the name in the dropdown. I imagine we would need to use Google AppScript. Any guidance in pointing me in the right direction would be appreciated.
A very generic script but you should be able to modify it as you see fit
function updateForm(){
var ss = SpreadsheetApp.openById('----------'); // ID of spreadsheet with names
var sheet = ss.getSheetByName('Names'); // Name of sheet with range of names
var nameValues = sheet.getRange('A2:A10').getValues(); // Get name values
var form = FormApp.openById('---------'); // ID of form
var formItems = form.getItems();
var question = formItems[2].asListItem(); // Get the second item on the from
var names = []
for(var x = 1; x < nameValues.length; x++){
if(nameValues[x][0] != ""){ // Ignores blank cells
names.push(question.createChoice(nameValues[x][0])) // Create an array of choice objects
}
}
var setQuestion1 = question.setChoices(names); // Update the question
}
To update the form when the sheet is edited you can use an installed onEdit trigger. With the addition of logic you can limit the updting of the form to only occour when a particular range has been edited.
In this example the form will only update when an edit has been made to column A of the sheet 'Names'
function updateForm(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var sheetName = sheet.getSheetName();
var getCol = e.range.getColumn();
if(sheetName == 'Names' && 1){
var nameValues = sheet.getRange('A2:A10').getValues(); // Get name values
var form = FormApp.openById('---------'); // ID of form
var formItems = form.getItems();
var question = formItems[2].asListItem(); // Get the second item on the from
var names = []
for(var x = 1; x < nameValues.length; x++){
if(nameValues[x][0] != ""){ // Ignores blank cells
names.push(question.createChoice(nameValues[x][0])) // Create an array of choice objects
}
}
var setQuestion1 = question.setChoices(names); // Update the question
}
}
I've been trying to code a function for a Google form that will send an email to a particular teacher that is indicated by the form. The problem is that I keep getting an error on a simple if statement. The error says, "Missing ; before statement. (line 29, file "Code")". The code is based on this Google Apps tutorial: https://developers.google.com/apps-script/articles/mail_merge#section-5-full-code. This is what I have right now:
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 4);
var templateSheet = ss.getSheets()[1];
var emailTemplate = templateSheet.getRange("A1").getValue();
// Create one JavaScript object per row of data.
var objects = getRowsData(dataSheet, dataRange);
// For every row object, create a personalized email from a template and send
// it to the appropriate person.
for (var i = 0; i < objects.length; ++i) {
// Get a row object
var rowData = objects[i];
// Generate a personalized email.
// Given a template string, replace markers (for instance ${"First Name"}) with
// the corresponding value in a row object (for instance rowData.firstName).
var emailText = fillInTemplateFromObject(emailTemplate, rowData);
var emailSubject = "Lab Visit Report";
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for (var i = 0; i < data.length; i++) {
var teacher = data[i][10];
If (teacher == "Jake Nabasny") {MailApp.sendEmail("JakeN#school.edu", emailSubject, emailText);}
else if (teacher == "Dan S") {MailApp.sendEmail("DanS#school.edu", emailSubject, emailText);}
}
}
I've already made sure that the variables (such as teacher and emailText) contain data. The problem, as far as I can tell, is solely with the if statement. Can anyone please give me an idea of what is going wrong here?
You seem to have capitialised an If ...
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);
}
}