Google form update response options instead of creating a new row - google-apps-script

I would like to edit a response option instead of adding a new response if the timestamp is already present in the reponse spreadsheet.
This is what i have tried.
function trial(event) {
var email = "xxxx#gmail.com";
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getDataRange().getValues();
var body = '';
//Comapring timestamp in each row with the timestamp entered in the form
var i = 0;
while(i < data.length) {
if(data[i][0].toString() == event.namedValues['Timstamp'].toString()){
body += '\n The row number: ' + i;
data[i][1] = 'ADDDDDDD';
data[i][2] = event.namedValues['Status'].toString();
ss.deleteRow(event.range.getRow());
}
i++;
}
var subject = "Delete Test";
GmailApp.sendEmail(email, subject, body);
}
I am entering the timestamp in the form as a value(I took care of passing the appropriate timestamp, user need not enter it; it would be prefilled). Now if there is a match, it deletes the new response but does not modify the old one. Can anyone point out my mistake.

Your script modifies the data array but doesn't write it back to the spreadsheet...that's why you don't see any change in the spreadsheet.
Just add a line after the loop to update the sheet with the appropriate data. I guess it could be something like
ss.getRange(1,1,data.length,data[0].length).setValues(data);

Related

Sending the same multiple emails instead of 1 email for loop bug

I have bug where when I run my send email function. its sending multiple emails instead of just one email notification here is my code what am I doing wrong??!?! I got 31 of the same emails. I believe the issue the for loop is sending an email each time the if statement is true instead of just one time if its true help.
here is my code:
function sendEmail(){
var ss = SpreadsheetApp.getActiveSpreadsheet(); //get active spreadsheet only! to get the url for the filter view
var SpreadsheetID = ss.getSheetId(); // get the sheet Id
var spreadsheetURL = ss.getUrl(); // get the current active sheet url
var SpreadsheetID = spreadsheetURL.split("/")[5]; // using the last / for getting the last parts of the email
var filterViewName = 'PO_Log Precentage'; // Name of the filter view you want to get the url from & MAKE SURE Title matches view name account for "spaces" too
var filterViewID = filterId(SpreadsheetID, filterViewName); // Getting filter view id
var url = createURL(spreadsheetURL, filterViewID); // creating the url to send the filter view id
Logger.log(url);// Testing to see the correct url is created
var po_numID = ss.getSheetByName("Purchase Orders List").getRange("A2").getDisplayValue().substr(0,3);// Gets the Purchase Order List Sheet and the PO# the first 3 Characters of the PO in A2
Logger.log(po_numID);
var email_va = ss.getSheetByName("Purchase Orders List");
//gonna build statuses to look for into array
var statusesToEmail = ['On-going', '']
//"Status" is in Column T (Col 2)
//"Precent" is in Column Q (Col 3)
var data = email_va.getDataRange().getValues()
// //var headerRowNumber = 1; // When checking for emails in the sheet you want to exclude the header/title row
var emailDataSheet = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/17G0QohHxjuAcZzwRtQ6AUW3aMTEvLnmTPs_USGcwvDA/edit#gid=1242890521").getSheetByName("TestA"); // Get The URL from another spreadsheet based on URL
Logger.log(emailDataSheet.getSheetName());
var emailData = emailDataSheet.getRange("A2:A").getDisplayValues().flat().map(po => po.substr(0,3));
Logger.log(emailData)///Working to get the first 3 charcters in column A
var subject = po_numID + " Po Log Daily Notification "; // Unique PoTitle of the email
var options = {} // Using the html body for the email
options.htmlBody = "Hi All, " + "The following" + '<a href=\"' +url+ '" > Purchase Orders </a>' + "are over 90% spent" + "";
for(var i = 0; i < data.length; i++){
let row = data[i];
if( statusesToEmail.includes(row[1]) & (row[2] >= .80)){
emailData.every((po, index) => {
if (po == po_numID){
const email = emailDataSheet.getRange(index + 2,7).getValue();//Getting the last colmun on the same row when the Po# are the same.
console.log(email);
MailApp.sendEmail(email, subject, '', options); // Sending the email which includes the url in options and sending it to the email address after making sure the first 3 Charcters Of the PO_log are the same as
return false;
} else {
return true;
}
});
}
}
}
here is the spreadsheet
https://docs.google.com/spreadsheets/d/1QW5PIGzy_NSh4MT3j_7PggxXq4XcW4dCKr4wKqIAp0E/edit#gid=611584429
you have to use the break function if u wish to stop the loop once the loop has been fulfiled, because if im not wrong , the email is sent if the IF condition is met , thus in the block that has mailapp.sendemail , you have to add in a break otherwise the loop will keep on happening. this is the basic of javascript and you should read up more about the FOR loop here
break as in just type "break" at the end of the code so the script will not continue to loop once the condition has been met.

Sending notification from google spreadsheet using time-driven events with condition

I would like to receive notifications when domain will expire. So I created a spreadsheet with a list of website and date of expiration. It has also a condition in Column A that when a domain is about to expire in 10 days it will appear Send notification as cell value. You can view my spreadsheet here.
With the values in column A, I would like to receive emails telling that the www.sample.com will expire on --some date here--.
For example, when Column A have new values equal to Send notification, then send email.
What I have tried and encountered:
var cell = sheet.getActiveCell().getA1Notation();
var row = sheet.getActiveRange().getRow();
var cellvalue = sheet.getActiveCell().getValue().toString();
var recipients = "youremail#gmail.com";
var domain = '';
var expirydate= '';
if(cell.indexOf('A')!=-1 && cell.indexOf('A') == 'Send notification'){
domain = sheet.getRange('B'+ sheet.getActiveCell().getRowIndex()).getValue();
expirydate = sheet.getRange('D'+ sheet.getActiveCell().getRowIndex()).getValue()
}
var subject = 'Expiry Notification : '+sheet.getName();
var body = 'Website will expire! ' + domain + ' is about to expire on ' + expirydate;
MailApp.sendEmail(recipients, subject, body);
Logger.log(body);
Trying this script only sends me notification without the value of the cell.
I would like this works even when the spreadsheet is not open / I am offline. So I guess I will be using the time driven event (every week).
Any help is much appreciated!
Prepare yourself, my answers tend to be long and explanatory.
Take this block:
if(cell.indexOf('A')!=-1 && cell.indexOf('A') == 'Send notification'){
domain = sheet.getRange('B'+ sheet.getActiveCell().getRowIndex()).getValue();
expirydate = sheet.getRange('D'+ sheet.getActiveCell().getRowIndex()).getValue()
}
In this block we can see that the if will always return FALSE. That is because cell.indexOf('A') cannot be a string, it will be an integer of the index. You want to be checking the value. I assume that is why you have the cellvalue variable.
Furthermore, your use of getRange() is also off. Why bother with A1 notation if you are getting indexes anyway. Instead I will go over the code and offer a different way of coding this.
Ok, let's start from the top of the code. You mentioned that you want this to run offline. We immediately get a problem here:
var cell = sheet.getActiveCell().getA1Notation();
this will be meaningless once you fire script based on a timer. I would recommend batching your data collection. First to be sure that you are not using getActiveSheet():
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Send notification')
OR
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0]
to get the first sheet or the sheet by it's name. Then we get the entire list into a 2D array.
var vals = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn()).getValues()
So we wish to check all domains. So now that we have all the values we wish to loop through them (we assume we left var domain and var expirydate as is)
var i
for (i = 0; i < vals.length; i++) {
if (vals[i][0] == 'Send notification!') {
domain = vals[i][1] //we get the domain name.
expirydate = vals[i][3] //we get the expire date
sendNotification(domain, expirydate); //use a seperate fu
}
}
where in the above block code I would seperate the function
function sendNotification(domain, expirydate) {
var subject = 'Expiry Notification : '+ domain;
var body = 'Website will expire! ' + domain + ' is about to expire on ' + expirydate;
MailApp.sendEmail(recipients, subject, body);
Logger.log(body);
}
of course you can leave the code inside of the for loop, but this will look cleaner. Also, I am not sure you really wanted var subject = 'Expiry Notification : '+sheet.getName(); because that will send all emails with the title Expiry Notification : Send notification because that is the sheet name (the tab at the bottom of the spreadsheet)

google apps script very very slow

I am using a google spreadsheet as a simple database of members and I want to create a user interface for searching through them (The primary users for this are not very technically adept and there is quite allot of data associated with each member so viewing it as a spreadsheet can be a bit tedius)
I have written the folowing script which worked last night but appears to run so slowly it times out today and I have no idea why.
function findMember() {
// set spreadsheet variable
var SS = SpreadsheetApp.getActiveSpreadsheet();
// set sheet variables
var memberSearchSheet = SS.getActiveSheet();
var memberDataSheet = SS.getSheetByName("Member Data");
// get the search variables
var searchFirstName = memberSearchSheet.getRange('C2').getValue();
var searchLastName = memberSearchSheet.getRange('C3').getValue();
// get last row of data
var lastRow = memberDataSheet.getLastRow();
for (var i = 2;lastRow;i=i+1){
if (searchFirstName == memberDataSheet.getRange('R'+i+'C2').getValue() && searchLastName == memberDataSheet.getRange('R'+i+'C3').getValue()){
memberSearchSheet.getRange('C5').setValue(memberDataSheet.getRange('R'+i+'C5').getValue());
//throw new Error("ouch")
}
}
// small pop up notification in bottom right corner .toast(message, title, display time)
//var message = "Your search for " + searchFirstName + " " + searchLastName + " is complete.";
//SS.toast(message,"Search Complete",15);
};
You can probably trying getting all the data inside an array in one step and then quickly compare your value with those in the array. Something like this:
var sheet = SpreadsheetApp.getActive().getSheetByName("Member Data");
var data = sheet.getDataRange().getValues();
for (var i = 1; i < data.length; i++) {
if (data[i][0] == firstName && data[i][1] == secondName) {
throw("Found");
}
}

Google Apps Script: Submit data into specified column

I am trying to find a script, or begin writing one, that takes a simple Google Form with a drop-down list of names (i.e. Tom, Jane) and a text area, and inputs both the date and the text into columns based on the selected name (i.e. Tom Date, Tom Comment). This is so I can make a quick entry feedback form for leaving individualized, date-based feedback for students, which they can then access later.
I looked through the GAS documentation and looked for examples, but as I am a novice, I really didn't know where to begin.
Any ideas on how to do this?
I think I did something similar but mine is for admins to observe teachers. I'm just learning as well, so I'm sure there are better ways to do this but it works. I definitely should have broken it up into more functions.
My form has a trigger to fire the onClose() when submitted. onClose() produces a Google Doc by reading the spreadsheet containing the form data in a nice format that the observer can then edit and share with the teacher. I wanted the Google Doc produced to have the name of the teacher being observed in the file name and I wanted it shared with the admin who did the observing.
The fact that some of the fields are dropdowns doesn't matter, it is just an itemResponse from the list of all responses.
function onClose()
{
var form = FormApp.openById(' whatever your form id is');
//the spreadsheet of the form responses
var formResponses = form.getResponses();
var d = new Date();
var currentTime = d.toLocaleTimeString();
var date = d.toLocaleDateString();
//Need to get the name of the teacher being observed
var formResponse = formResponses[formResponses.length-1];
var itemResponses = formResponse.getItemResponses();
var itemResponse = itemResponses[0]; //the teacher name dropdown box
var teacherName = itemResponse.getResponse() + '-' + itemResponses[1].getResponse();
//create the new document
var fileName = 'Observation-'+ teacherName + '-' + date + '-' + currentTime;
var doc = DocumentApp.create(fileName);
var activeDoc = DocumentApp.getActiveDocument();
var files = DriveApp.getFilesByName(fileName);
while (files.hasNext()) {
var file = files.next();
if (file.getName().equals(fileName))
{
//this is the last item on my form the name of the observer
var itemResponse21 = itemResponses[21];
var observer = itemResponse21.getResponse();
// Logger.log('Person to share with is ' + observer);
// share this google doc with the observer
file.addEditor(observer);
}
}
//ommittd a bunch of styles
//This would get all forms submitted, but I only need the last one
// so I just set the loop to get the last form submitted.
//leaving for loop just so I remember I can go through all forms again
//if I want to.
for (var i = formResponses.length-1; i < formResponses.length; i++) {
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
//get the individual responses within the form.addCheckboxItem()
for (var j = 0; j < itemResponses.length; j++) {
//pull the first item out again (even though I did for file name)
var itemResponse = itemResponses[j]; //teacher name from a dropbox
var itemResponse2 = itemResponses[j+1]; //date
var itemResponse3 = itemResponses[j+2]; //time
if (j == 0) //the first field on the form
{
//put the headings in
par3 = doc.appendParagraph(' SCHOOL NAME');
par3 = doc.appendParagraph('WALK IN OBSERVATION');
par3 = doc.appendParagraph('2013-2014');
//THIS is the teacher being observed and the date and time --- all on same line
var headingLine = itemResponse.getItem().getTitle() + '\t\t' + itemResponse2.getItem().getTitle() + ' / ' + itemResponse3.getItem().getTitle();
par1 = doc.appendParagraph(headingLine);
var answerLine = itemResponse.getResponse() + '\t\t\t\t\t' + itemResponse2.getResponse() + ' / ' + itemResponse3.getResponse();
par2 = doc.appendParagraph(answerLine);
j++; //do this to skip over date and time
j++;
} //end of j = 0;
else
// then I have a bunch of if statements for some of the
// specific fields I need to do something special with.
// After the last if, I just have an else to handle all other
// form responses that I don't do anything special for other than display.
//my last else is:
else
//THIS ELSE IS HANDLING ALL NON CHECK BOXES AND JUST DISPLAYING THE TITLE IN BOLD FONT, THE COMMENTS IN REGULAR FONT
{
par1 = doc.appendParagraph(itemResponse.getItem().getTitle());
par1.setAttributes(style);
par2 = doc.appendParagraph( itemResponse.getResponse());
par2.setAttributes(style);
} //END OF ELSE
} //end of for going through each cell in a row of the repsonses
} //end of for going through each row -- only had it set to do the very last row

Create timestamp with script editor when email is sent by Google Spreadsheet

I am currently receiving data through an RSS feed into my spreadsheet. I have a script (below) which I am hoping to run on a time trigger (every minute) to check the data and then in turn send an email out if the data meets certain criteria.
Problem: After the first email is sent out, I want to create a system to check (timestamp?) within the script if an email for that particular row of data has already been sent. Is this the best way to do this? How do I do it? Script is below.
function sendEmail(email_address, email_subject, email_message) {
MailApp.sendEmail(email_address, email_subject, email_message);
}
function test_sendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.setActiveCell('A2');
var criterion_cutoff = 5;
var i = 0;
var addr;
var subj;
var msg;
do {
addr = cell.offset(i,0).getValue();
subj = cell.offset(i,1).getValue();
msg = cell.offset(i,2).getValue();
criterion = cell.offset(i,3).getValue();
if(criterion < criterion_cutoff) {
sendEmail(addr,subj,msg);
Browser.msgBox('Sending email to: ' + addr);
}
i++;
} while( cell.offset(i, 0).getValue().length > 0 )
Browser.msgBox('Done!');
}
If I'm understanding your question correctly, you want some way of marking which rows in the spreadsheet that you've already sent emails for, so that you don't send duplicates. If so, then this tutorial shows one way of doing that: https://developers.google.com/apps-script/articles/sending_emails#section2