Google Apps Script - Email when row in Google sheet is updated - email

I am a teacher and new to programing script. I have a sheet named 'Scores' in a Google spreadsheet that has a list of emails in column A and an array of data in the following columns. When any data in B:R is changed I would like to automatically send an email to the address listed in column A of the row that changed in this sheet that includes the data in that row and associated column headers.
Example.
Send Email to address in 'A4'
Subject line: Undated Scores
A string of text as a greeting.
Create a table with 'column headers' and 'Row Data'
B1 - B4
C1 - C4
D1 - D4
...to last column
Thanks

You will have to compose the subject and the message with the information found in data. The index for data is one less than the column number. If you wish to learn more about the onedit event object try adding console.log(JSON.stringify(e)) to the second line and it will print in the execution log. I like to use Utilties.formatString() when composing text mixed in with merged data.
//function will only run with you in the correct sheet and you edit any cell from b to r or 2 to 18
function sendEmailWhenBRChanges(e) {
const sh=e.range.getSheet();
const startRow=2;//wherever your data starts
if(sh.getName()=='Your Sheet Name' && e.range.columnStart>1 && e.range.columnStart<19 e.range.rowStart>=startRow) {
let data=sh.getRange(e.range.rowStart,1,1,18).getValues()[0];//data is now in a flattened array
//compose subject and message here if you want html then use the options object
GmailApp.sendEmail(data[0],Subject,Message);
}
}
on edit event object
Note you will have to create an installable trigger because sending email requires permission. You can create the trigger programmatically using ScriptApp.newTrigger() or go to the triggers section of the new editor or the edit menu in the legacy editor and don't forget to put the e in the parameters section of the function declaration.
Also please note that you cannot run this function directly from the script editor because it requires the event object that it gets from the trigger.
I know this is what you asked for but your not going to like it because it will trigger the email to be send whenever to edit any of the columns. You will probably prefer changing it later to accommodate putting a column of checkboxes which can be used as buttons for sending the emails.

Related

Google Sheet notification when a cell in a particular column is edited

I have google sheet where i would like to have an email notification been sent to a specified user whenever a cell in particular column has been edited.
The sheets contains 15 columns and one of the column is for comments and another for email address.
My requirement is whenever any cells in the comment column is edited, I would like to have an email sent to email address mentioned in a different column of the same sheet.
I did went over few of thread and found this thread had similar problem and has been successfully answered with a code. However, when i used this script it gives a a "Cannot read property 'range' of undefined (line 2, file "Code")" message.
I'm a noob to coding and not sure what does that means.
I also tried Magic Cell Notification addon but to no avail.
Any help will be greatly appreciated.
Send Email
You need to create an installable trigger for onMyEdit.
You need to provide the sheet name, the emailColumn, the commentColumn, the startingRow for data, the and the subject.
And please realize that you can't call this function from the script editor as it requires the event block from the onedit trigger.
`
function onMyEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()!='Your Sheet Name')return;
var emailColumn=1;//you have to tell me what column the email is on
var commentColumn=2;//you have to tell me what column the comment is on
var startingRow=2;//you have to tell me what row the data starts on
var subject='You tell me what the subject is';
if(e.range.columnStart==emailColumn && e.range.rowStart>startingRow && e.value) {
GmailApp.sendEmail(sh.getRange(e.range.rowStart,emailColumn).getValue(), subject, sh.getRange(e.range.rowStart,commentColumn));
}
}

updating existing data on google spreadsheet using a form?

I want to build kind of an automatic system to update some race results for a championship. I have an automated spreadsheet were all the results are shown but it takes me a lot to update all of them so I was wondering if it would be possible to make a form in order to update them more easily.
In the form I will enter the driver name and the number o points he won on a race. The championship has 4 races each month so yea, my question is if you guys know a way to update an existing data (stored in a spreadsheet) using a form. Lets say that in the first race, the driver 'X' won 10 points. I will insert this data in a form and then call it from the spreadsheet to show it up, that's right. The problem comes when I want to update the second race results and so on. If the driver 'X' gets on the second race 12 points, is there a way to update the previous 10 points of that driver and put 22 points instead? Or can I add the second race result to the first one automatically? I mean, if I insert on the form the second race results can it look for the driver 'X' entry and add this points to the ones that it previously had. Dunno if it's possible or not.
Maybe I can do it in another way. Any help will be much appreciated!
Thanks.
Maybe I missed something in your question but I don't really understand Harold's answer...
Here is a code that does strictly what you asked for, it counts the total cumulative value of 4 numbers entered in a form and shows it on a Spreadsheet.
I called the 4 questions "race number 1", "race number 2" ... and the result comes on row 2 so you can setup headers.
I striped out any non numeric character so you can type responses more freely, only numbers will be retained.
form here and SS here (raw results in sheet1 and count in Sheet2)
script goes in spreadsheet and is triggered by an onFormSubmit trigger.
function onFormSubmit(e) {
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2');
var responses = []
responses[0] = Number(e.namedValues['race number 1'].toString().replace(/\D/g,''));
responses[1] = Number(e.namedValues['race number 2'].toString().replace(/\D/g,''));
responses[2] = Number(e.namedValues['race number 3'].toString().replace(/\D/g,''));
responses[3] = Number(e.namedValues['race number 4'].toString().replace(/\D/g,''));
var totals = sh.getRange(2,1,1,responses.length).getValues();
for(var n in responses){
totals[0][n]+=responses[n];
}
sh.getRange(2,1,1,responses.length).setValues(totals);
}
edit : I changed the code to allow you to change easily the number of responses... range will update automatically.
EDIT 2 : a version that accepts empty responses using an "if" condition on result:
function onFormSubmit(e) {
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2');
var responses = []
responses[0] = Number((e.namedValues['race number 1']==null ? 0 :e.namedValues['race number 1']).toString().replace(/\D/g,''));
responses[1] = Number((e.namedValues['race number 2']==null ? 0 :e.namedValues['race number 2']).toString().replace(/\D/g,''));
responses[2] = Number((e.namedValues['race number 3']==null ? 0 :e.namedValues['race number 3']).toString().replace(/\D/g,''));
responses[3] = Number((e.namedValues['race number 4']==null ? 0 :e.namedValues['race number 4']).toString().replace(/\D/g,''));
var totals = sh.getRange(2,1,1,responses.length).getValues();
for(var n in responses){
totals[0][n]+=responses[n];
}
sh.getRange(2,1,1,responses.length).setValues(totals);
}
I believe you can found everything you want here.
It's a form url, when you answer this form you'll have the url of the spreadsheet where the data are stored. One of the information stored is the url to modify your response, if you follow the link it will open the form again and update the spreadsheet in consequence. the code to do this trick is in the second sheet of the spreadsheet.
It's a google apps script code that need to be associated within the form and triggered with an onFormSubmit trigger.
It may be too late now. I believe we need a few things (I have not tried it)
A unique key to map each submitted response, such as User's ID or email.
Two Google Forms:
a. To request the unique key
b. To retrieve relevant data with that unique key
Create a pre-filled URL (See http://www.cagrimmett.com/til/2016/07/07/autofill-google-forms.html)
Open the URL from your form (See Google Apps Script to open a URL)

Get details of cells changed from a Google Spreadsheet change notification in a machine readable format

If I have a Google Spreadsheet e.g.
https://docs.google.com/spreadsheet/ccc?key=0AjAdgux-AqYvdE01Ni1pSTJuZm5YVkJIbl9hZ21PN2c&usp=sharing
And I have set up notifications on it to email me immediately whenever a cell changes.
And I make a change to that spreadsheet via the spreadsheet API - i.e. not by hand.
Then I get an email like this:
Subject: "Notification Test" was edited recently
See the changes in your Google Document "Notification Test": Click
here
other person made changes from 10/01/2014 12:23 to 12:23 (Greenwich
Mean Time)
Values changed
If I open the 'Click here' link then I get this URL which shows me the cell that has changed in the spreadsheet:
https://docs.google.com/a/DOMAINGOESHERE/spreadsheet/ver?key=tn9EJJrk6KnJrAEFaHI8E3w&t=1389356641198000&pt=1389356621198000&diffWidget=true&s=AJVazbUOm5tHikrxX-bQ0oK_XEapjEUb-g
My question is:
Is there a way to get the information about which cell has changed in a format that I can work with programmatically- e.g. JSON?
I have looked through the Google Spreadsheet API:
https://developers.google.com/google-apps/spreadsheets/
and at the Drive API Revisions:
https://developers.google.com/drive/manage-revisions
I have also tried setting up an onEdit() event using Google Apps Script: https://developers.google.com/apps-script/understanding_triggers
I thought this last approach would be the answer.
The problem with this approach is that whilst onEdit can be used to email details of changes, it appears to only be fired if the spreadsheet is edited by hand whereas mine is being updated programmatically via the spreadsheet API.
Any ideas?
You could build a function that checks for changes. One way to do this is by comparing multiple instances of the same spreadsheet. If there are differences, you could email yourself. Using the time driven trigger, you can check every minute, hour, day, or week (depending on your needs).
var sheet = **whatever**;//The spreadsheet where you will be making changes
var range = **whatever**;//The range that you will be checking for changes
var compSheet = **whatever**;//The sheet that you will compare with for changes
function checkMatch(){
var myCurrent = sheet.getRange(range).getValues();
var myComparison = compSheet.getRange(range).getvalues();
if(myCurrent == myComparison){//Checks to see if there are any differences
for(i=0;i<compSheet.length;++i){ //Since getValues returns a 'multi-dimensional' array, 2 for loops are used to compare each element
for(j=0;j<compSheet[i].length;++i){
if(myCurrent[i][j] != myComparison[i][j]){//Determines if there is a difference;
//***Whatever you want to do with the differences, put them here***
}
}
myEmailer(sheet.getUrl());//Passes the url of sheet to youur emailer function
compSheet.getRange(range).setValues(myCurrent);//Updates compSheet so that next time is can check for the next series of changes
}
}
Then from Resources>Current project's triggers you can set checkMatch to run every minute.
Also check out https://developers.google.com/gdata/samples/spreadsheet_sample for pulling data as json

Extract portions of Google Docs form data and write it on separate lines

Let's say I have a Google Docs Form that gathers the following info:
Timestamp (default field)
Names
Ref#
The form data then appears on the spreadsheet as follows:
4/10/2013 16:20:31 | Jack, Jill, Oscar | Ref6656X
(Note: the number of names may be anywhere from 1 to many)
I need the data to appear on the spreadsheet as follows:
4/10/2013 16:20:31 | Jack | Ref6656X
4/10/2013 16:20:31 | Jill | Ref6656X
4/10/2013 16:20:31 | Oscar | Ref6656X
I can often decipher and edit Google Apps Script (JavaScript?), but I don't know how to think in that language in order to create it for myself (especially with an unknown number of names in the Name field). How can I get started on solving this?
First of all, you've got some choices to make before you start writing your code.
Do you want to modify the spreadsheet that's accepting form input, or produce a separate sheet that has the modified data? If you want to have a record of what was actually input by a user, you'd best leave the original data alone. If you're using a second sheet for the massaged output, the presence of multiple tabs might be confusing to your users, unless you take steps to hide it.
Do you want to do the modifications as forms come in, or (in bulk) at some point afterwards? If you already have collected data, you'll have to have the bulk processing, and that will involve looping and having to handle insertions of new rows in the middle of things. To handle forms as they come in, you'll need to set up a function that is triggered by form submissions, and only extend the table further down... but you've got more learning to do - see Container-Specific Triggers, Understanding Triggers and Understanding Events for background info.
Will you primarily use Spreadsheet service functions, or javascript Arrays? This choice is often about speed - the more you can do in javascript, the faster your script will be, but switching between the two can be confusing at first.
Here's an example function to do bulk processing. It reads all existing data into an array, goes through that and copies all rows into a new array, expanding multiple names into multiple rows. When done, the existing sheet data is overwritten. (Note - not debugged or tested.)
function bulkProcess() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataIn = ss.getDataRange().getValues();
var dataOut = [];
for (var row in dataIn) { // Could use: for (var row = 0; row < dataIn.length; row++)
var names = dataIn[row][1].split(','); // array of names in second column
var rowOut = dataIn[row];
for (var i in names) {
rowOut[1] = names[i]; // overwrite with single name
dataOut.push(rowOut); // then copy to dataOut array
}
}
// Write the updated array back to spreadsheet, overwriting existing values.
ss.getRange(1,1,dataOut.length,dataOut[0].length).setValues(dataOut);
}

Access 2010 Trying to Enter a unique record through Form

I'm trying to input an error check for my form. I have the user entering the name and I would like a prompt to inform them if they are attempting to use a Name already in the records.
Example: the Person table has 3 records with FNames being: Jeff, Kyle, Darren.
If on the add person form in the Fname Box Kyle is entered, the after update event will notify the user that this name has been claimed and null the field. Where as if Greg was enter no notifications will occur.
I just don't know how to compare a text field value to values in a filtered query list, and Google searches have other loosely related links in the way.
Thank you for help!
If all fnames must be unique, add a unique index to the table. This will prevent duplicates being entered. The form error property will allow you to provide a custom error.
You can also check if the name exists in the Before Update event of the control.
In this example, the control and field are both called AText. Generally, you should rename controls so they are not the same as fields.
Private Sub AText_BeforeUpdate(Cancel As Integer)
Dim IsOk As Boolean
''One of the very few places where the .Text property is used
sLookUp = Me.AText.Text
IsOk = IsNull(DLookup("Atext", "Table1", "Atext='" & sLookUp & "'"))
If Not IsOk Then
MsgBox "Found!"
Cancel = True
End If
End Sub