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
Related
I have some production code that I am repurposing. Currently, it processes everything based on the gmail label and puts a specified portion into a spreadsheet. This will not change (though it could if that was the best way to solve this problem).
I now need to process a subset of those messages and put a portion of the message body into a spreadsheet.
The body of the text is as follows:
This is an email alarm.
Room Lights OFF.
(Other examples might say "Room Lights ON", "ALARM", or "OK".
I only need to get the portion of the body after "Room Lights".
Also included in this gmail label are emails that do not mention "Room Lights" at all. These should be ignored and not added to the spreadsheet.
Example:
This is an email alarm.
Network has returned.
or
This is an email alarm.
Generator is OFF.
Question: How can I edit my code so that only "Room Lights" emails are added to the spreadsheet?
Example code:
function lightFunction() {
newMonth();
var label = GmailApp.getUserLabelByName("Lights");
var label2 = GmailApp.getUserLabelByName("Processed");
var threads = label.getThreads();
var data = new Array();
var newData = new Array();
var alarmKeys = "This is an email alarm.";
var keys = alarmKeys.split(",");
var range = "A2:B";
// get all the email threads matching label
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
// archive thread
// label2.addToThread(threads[i]);
// label.removeFromThread(threads[i]);
// get each individual email from the threads
for (var j = 0; j < messages.length; j++) {
var bodyText = messages[j].getPlainBody();
for (k in keys) {
bodyText = bodyText.replace(keys[k], "");
}
bodyText = bodyText.trim();
var date = messages[j].getDate(); // date/time
var lines = [date, bodyText];
// Turn the first element in the array into a date element, format it, and put it back
lines[0] = Utilities.formatDate(new Date(lines[0]), "America/Phoenix", "M/d/yy HH:mm:ss");
// Put the array to a new item in the data array for further processing
if (curMonth == (new Date(lines[0]).getMonth())) {
data.push(lines);
}
}
}
checkAdd(data, range);
}
ALTERNATE METHOD
You could also tweak the part with data.push(lines); with regex using a match method in one line, something like this:
lines[1].match(/Room Lights|OK|ALARM/gm) ? data.push(lines) : null;
You may also check this sample regex test.
In my understanding here is the flow:
Read emails under labels Lights / Processed
Check each email that may match the following texts:
"Room Lights OFF", "Room Lights ON", "ALARM", or "OK"
Only add the matched emails on the spreadsheet
Tweaked Script
function lightFunction() {
newMonth();
var curMonth = new Date().getMonth()
var label = GmailApp.getUserLabelByName("Lights");
var label2 = GmailApp.getUserLabelByName("Processed");
var threads = label.getThreads();
var data = new Array();
var newData = new Array();
var alarmKeys = "This is an email alarm.";
var keys = alarmKeys.split(",");
var range = "A2:B";
// get all the email threads matching label
for (var i = 0; i < threads.length; i++) {
var messages = GmailApp.getMessagesForThread(threads[i]);
// archive thread
// label2.addToThread(threads[i]);
// label.removeFromThread(threads[i]);
// get each individual email from the threads
for (var j = 0; j < messages.length; j++) {
var bodyText = messages[j].getPlainBody();
for (k in keys) {
bodyText = bodyText.replace(keys[k], "");
}
bodyText = bodyText.trim();
var date = messages[j].getDate(); // date/time
var lines = [date, bodyText];
// Turn the first element in the array into a date element, format it, and put it back
lines[0] = Utilities.formatDate(new Date(lines[0]), "America/Phoenix", "M/d/yy HH:mm:ss");
// Put the array to a new item in the data array for further processing
if (curMonth == (new Date(lines[0]).getMonth())) {
//Tweaked part
lines[1].match(/Room Lights|OK|ALARM/gm) ? data.push(lines) : null;
//Tweaked part
}
}
}
checkAdd(data, range);
}
Demonstration
Sample emails
Log test of the data variable
References
Match
Regex
Conditional (ternary) operator
Although I'm not sure whether I could correctly understand your showing script, if your data is used in checkAdd(data, range); and data is put to the Spreadsheet, and you want to filter data by Question: How can I edit my code so that only "Room Lights" emails are added to the spreadsheet?, how about the following modification?
From:
var bodyText = messages[j].getPlainBody();
To:
var bodyText = messages[j].getPlainBody();
if (!bodyText.includes("Room Lights")) continue;
Or, if you want to check multiple texts, how about the following modification?
var bodyText = messages[j].getPlainBody();
var searchTexts = ["Room Lights", "sample",,,]; // Please set search texts you want.
if (!searchTexts.some(e => bodyText.includes(e))) continue;
Reference:
includes()
I have created a template with several pages. After the template is used, I want to automatically remove any unused page.
This is how it works. I have created a certificate template with 25 pages with placeholders for name and other details. Each page is a certificate. After going through the data, the code below replaces the placeholders with data from the Google Sheets. Once that is completed - I want to remove all the extra pages in the document - for example: if only 5 template pages are modified, I want to remove the remaining 20 template pages from the document.
Any other improvement suggestions are welcome as this is my first App Script.
Addition to clarify the question:
The script takes data from a Google Sheet which has hundreds of rows of data. For example, if 5 certificates need to be created, the script gets all the data and loop and look for a certain flag (cert_data[i][6] == 1) to identify the rows of data that should be used for the certificate. Once the flag is found, the data in the row are stored in variables and is used to replace the place holders in the template file. Once the data in all flagged rows are replaced - for this example, only 5 template pages are replaced. Hence there will be a balance of 20 pages in the template that has not been used - I want to delete these pages.
function createDocument() {
//Setting ID for database
var SPREADSHEET_ID = "doc ID"
var spreadsheet = SpreadsheetApp.openById(SPREADSHEET_ID);
var worksheet = spreadsheet.getSheetByName("Sheet1");
var cert_data = worksheet.getDataRange().getValues();
//Setting template ID
var templateId = 'template ID goes here';
//Make a copy of the template file
var documentId = DriveApp.getFileById(templateId).makeCopy().getId();
//Get the document body as a variable
var body = DocumentApp.openById(documentId).getBody();
//Foramt date
var curDate = Utilities.formatDate(new Date(), "GMT+1", "dd MMMM yyyy")
var d = 0;
//Looping through all the data that is in the Google Sheet
for(var i = 1; i < cert_data.length ; i++){
var curdata = cert_data[i][6];
//Checking if the row data is to be used to create certificate
if (cert_data[i][6] == 1) {
var training_type = cert_data[i][12];
var hours = cert_data[i][9];
var user_name = cert_data[i][1];
var NIC = cert_data[i][3];
var date_completed = Utilities.formatDate(cert_data[i][8], "GMT+1", "dd MMMM yyyy");
var company = cert_data[i][2];
var cert_number = cert_data[i][0];
var date_now = curDate;
//Setting training names
if (training_type == "01G") {training_type = "Basic First Aid" + String.fromCharCode(10) + "& Automated External" + String.fromCharCode(10) + "Defibrillator Certificate"; var file_name = 'AED Training';}
if (training_type == "01B") {var file_name = 'Refresher Receipts';}
d++;
//Insert the data into the file
body.replaceText('{training_type' + d + '}', training_type);
body.replaceText('{hours' + d + '}', hours);
body.replaceText('{name' + d + '}', user_name);
body.replaceText('{NIC' + d + '}', NIC);
body.replaceText('{date_completed' + d + '}', date_completed);
body.replaceText('{company' + d + '}', company);
body.replaceText('{cert_numb' + d + '}', cert_number);
body.replaceText('{date_now' + d + '}', date_now);
}
}
//d is the number of pages used from the template file
//I want to delete all the balance pages (i.e. 25-d = x)
//Rename the copied file
DriveApp.getFileById(documentId).setName(file_name + ' - ' + company);
}
Each page of your Google Document is separated by the page breaks.
You want to delete several pages of Google Document from the last page in order.
Number of pages you want to delete is decided by your script.
If my understanding is correct, how about this sample script? The flow of this script is as follows.
Flow:
Retrieve paragraphs in the body of Document.
Retrieve elements in each paragraph. The page break is included in the paragraph.
Delete elements from last page in order.
When the number of page breaks is the same with deletePages, the script is stopped.
By this flow, several pages can be deleted from the last page in order.
Sample script:
Please copy&paste the following script and set the variables of deletePages and id. Then, run the script.
function myFunction() {
var deletePages = 3;
var id = "### documentId ###";
var paragraph = DocumentApp.openById(id)
.getBody()
.getParagraphs();
var counter = 0;
for (var i = paragraph.length - 1; i >= 0; i--) {
for (var j = 0; j < paragraph[i].getNumChildren(); j++)
if (
paragraph[i].getChild(j).getType() == DocumentApp.ElementType.PAGE_BREAK
)
counter++;
if (counter < deletePages)
paragraph[i].clear();
else if (counter == deletePages){
paragraph[i].getChild(paragraph[i].getNumChildren() - 1).removeFromParent();
break;
}
}
}
Note:
If you want to delete 5 pages from the last page, please set var deletePages = 5.
Also you can use this function like myFunction(deletePages) as a method. At that time, please remove var deletePages = 3;.
You can also use DocumentApp.getActiveDocument() instead of DocumentApp.openById(id).
From #derekantrican's suggestion, I updated the sample script.
References:
getParagraphs()
getChild()
clear()
I have this function running in a Google Sheets script that pulls HTML from subreddits and returns them to a spreadsheet. It works for me some/most of the time, but other times I get an error "Could not parse text. (line 13)" which is the line with var doc = Xml.parse(page, true);. Any idea why this is happening or is this just a bug with Google Scripts? Here's the code that works...sometimes.
function getRedditHTML() {
var entries_array = [];
var subreddit_array = ['https://www.reddit.com/r/news/','https://www.reddit.com/r/funny/','https://www.reddit.com/r/science/'];
for (var s = 0; s < subreddit_array.length; s++) {
var page = UrlFetchApp.fetch(subreddit_array[s]);
//this is Line 13 that is breaking
var doc = Xml.parse(page, true);
var bodyHtml = doc.html.body.toXmlString();
doc = XmlService.parse(bodyHtml);
var root = doc.getRootElement();
var entries = getElementsByClassName(root,'thing');
for (var i = 0; i < entries.length; i++) {
var title = getElementsByClassName(entries[i],'title');
title = XmlService.getRawFormat().format(title[1]).replace(/<[^>]*>/g, "");
var link = getElementsByClassName(entries[i],'comments');
link = link[0].getAttribute('href').getValue();
var rank = getElementsByClassName(entries[i],'rank');
rank = rank[0].getValue();
var likes = getElementsByClassName(entries[i],'likes');
likes = likes[0].getValue();
entries_array.push([rank, likes, title, link]);
}
}
return entries_array.sort(function (a, b) {
return b[1] - a[1];
});
}
Here is what I found upon playing with importXML (my usual way of doing this) - for some reason I cannot narrow down - it DOES appear to randomly stall out and return null for a few minutes - so I'm guessing the issue with your thing is not the code but that the site or google temporarily blocks/won't return the data -
however I found the JSON endpoint to the piece you want - and I noticed that when XML went down - the JSON didnt.
You can take that and fix it to push your own array of topics/urls - I just left it for one link for now to show you how the URL breaks down and where it should be modified:
The URL is 'https://www.reddit.com/r/news/hot.json?raw_json=1&subredditName=news&sort=top&t=day&feature=link_preview&sr_detail=true&app=mweb-client
News is mentioned in 2 places so just modify all your URLs to follow that method - you can easily load that javascript in a browser to see all the fields available
Also the portion hot.json is where you can change whether you want the ranked list (called hot), or new,top,promoted, etc. you just change that keyword.
Score is the same as the upvotes/likes
function getSubReddit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet(); //get Active sheet
var subject = 'news';
var url = 'https://www.reddit.com/r/' + subject + '/hot.json?raw_json=1&subredditName=' + subject + '&sort=top&t=day&feature=link_preview&sr_detail=true&app=mweb-client'; //json endpoint for data
var response = UrlFetchApp.fetch(url); // get api endpoint
var json = response.getContentText(); // get the response content as text
var redditData = JSON.parse(json); //parse text into json
Logger.log(redditData); //log data to logger to check
//create empty array to hold data points
var statsRows = [];
var date = new Date(); //create new date for timestamp
//The following lines push the parsed json into empty stats array
for (var j=0;j<25;j++){
for (var i =0;i<25;i++){
var stats=[];
stats.push(date);//timestamp
stats.push(i+1);
stats.push(redditData.data.children[i].data.score); //score
stats.push(redditData.data.children[i].data.title); //title
stats.push(redditData.data.children[i].data.url); //article url
// stats.push('http://www.reddit.com' + redditData.data.children[i].data.permalink); //reddit permalink
statsRows.push(stats)
}
//append the stats array to the active sheet
sheet.appendRow(statsRows[j])
}
}
I have a script that is designed to create about 120 forms and link them to a single spreadsheet where I will analyze the data. I don't have any issues with the script until my spreadsheet has about a dozen forms linked to it. Then I get an error saying the destination ID is invalid, after logging the id, and entering it manually into a url I see no issues with the ID....
var ssSummaryId = '******redacted*******';
var form = FormApp.create('RM#' + rmNumber).setDestination(FormApp.DestinationType.SPREADSHEET, ssSummaryId);
form.setDescription(valuesSummary[ii][2])
.setConfirmationMessage('Thanks for the update on room ' + rmNumber)
.setShowLinkToRespondAgain(false);
// form.setDestination(FormApp.DestinationType.SPREADSHEET, ssSummaryId);
var formId = form.getId();
var formUrl = form.getPublishedUrl();
EDIT I'm adding my complete script and some additional info, just in case someone wants to check my code out and point out all it rookie mistakes.
I'm using Google scripts to build a spreadsheet and then create 120 slightly altered Google forms that are linked to a single spreadsheet, all the responses are by design on separate sheets named "form responses n". I consistently hit a wall once I exceed 10 forms linked to one sheet. Note; in initial testing I remember having a spreadsheet with 46 forms (and therefore sheets) linked to it. As you can see in the code below, I have the app restart from where it's left off after every 5 forms are created, so I'm not getting any 'extended runtime errors". Just the error below, typically after the script runs twice from Google Scripts IDE.
I'm just finally getting the hand of basic javascript after years of using and modifying js in web developing. So I apologize in advanced for the poor code.
Failed to set response destination. Verify the destination ID and try again. (line 54, file "Code")
function spreadsheet_builder() {
var ssSummaryId = '<<REDACTED>>';
var ssFormDataId = '<<REDACTED>>';
var batchSize = 5;
var buildStatus = false;
var ssSummary = SpreadsheetApp.openById(ssSummaryId);
SpreadsheetApp.setActiveSpreadsheet(ssSummary);
if (ssSummary.getSheetByName('Summary') == null) {
var sheetSummary = ssSummary.getSheetByName('Sheet1');
} else {
var sheetSummary = ssSummary.getSheetByName('Summary');
}
var rangeSummary = sheetSummary.getDataRange();
var valuesSummary = rangeSummary.getValues();
buildStatus = get_last_position(valuesSummary, buildStatus); //either returns last position in array or 'true' if task is complete
if (buildStatus != true || buildStatus > 0) {
var formCreation = [];
var formData = get_form_data(ssFormDataId); // Get form questions from form Data ss, might be better to keep everything on the same sheet
batchSize = buildStatus + batchSize;
for ( var ii = buildStatus; ii < batchSize; ii++ ) {
if (valuesSummary[ii][1] != '') {
var formCreationReturn = form_builder(formData, valuesSummary, ii, ssSummaryId);
formCreation.push(formCreationReturn);
}
}
var aSum = [ssSummary, sheetSummary, rangeSummary];
final_storing_operation(formCreation, aSum, buildStatus);
}
if (sheetSummary.getName() != 'Summary') {
SpreadsheetApp.setActiveSpreadsheet(ssSummary);
sheetSummary.activate().setName('Summary');
sheetSummary.setFrozenColumns(3);
sheetSummary.setFrozenRows(1);
sheetSummary.hideColumns(1);
//var sSumIndex = sheetSummary.getIndex();
}
SpreadsheetApp.setActiveSpreadsheet(ssSummary);
sheetSummary.activate();
ssSummary.moveActiveSheet(1);
}
function form_builder(formData, valuesSummary, ii, ssSummaryId) {
var lastFormCreated = ii;
var rmNumber = valuesSummary[ii][1];
var form = FormApp.create('RM#' + rmNumber).setDestination(FormApp.DestinationType.SPREADSHEET, ssSummaryId);
form.setDescription(valuesSummary[ii][2])
.setConfirmationMessage('Thanks for the update on room ' + rmNumber)
.setShowLinkToRespondAgain(false);
// form.setDestination(FormApp.DestinationType.SPREADSHEET, ssSummaryId);
var formId = form.getId();
var formUrl = form.getPublishedUrl();
var sectionHeader = 'SECTION_HEADER'; //preformatted form question types.
var list = 'LIST';
var paragraphText = 'PARAGRAPH_TEXT';
for (var j = 1; j < formData.length; j++) { //top row is header
switch (formData[j][0]) {
case sectionHeader:
form.addSectionHeaderItem().setTitle(formData[j][1]);
break;
case list:
var item = form.addListItem();
item.setTitle(formData[j][1]).setHelpText(formData[j][2]);
item.setChoices([
item.createChoice(formData[j][3]),
item.createChoice(formData[j][4]),
item.createChoice(formData[j][5])
]);
break;
case paragraphText:
form.addParagraphTextItem().setTitle(formData[j][1]);
break;
default:
form.addSectionHeaderItem().setTitle('OOPS u\'don MESSED up');
break;
}
}
return [formId, formUrl, lastFormCreated, rmNumber];
}
function final_storing_operation(formCreation, aSum, buildStatus) {
SpreadsheetApp.setActiveSpreadsheet(aSum[0]);
aSum[1].activate();
var startRow = formCreation[0][2] + 1;
var newRange = aSum[1].getRange(startRow, 1, formCreation.length, 2); //row, clmn, rows, columns
var newValues = [];
for ( var ij = 0; ij < formCreation.length; ij++) {
var values = [formCreation[ij][0], "\=HYPERLINK(\"" + formCreation[ij][1] + "\", \"RM#" + formCreation[ij][3] + "\")"];
newValues.push(values);
}
newRange.setValues(newValues);
}
function get_last_position (valuesSummary, buildStatus) {
var rowPos = 1; // start at 1 to ignore headers
while (valuesSummary[rowPos][1] != '') {
if (valuesSummary[rowPos][0] == '') {
return rowPos;
}
rowPos++;
}
if(valuesSummary[rowPos][0] != '' && valuesSummary[rowPos][1] != '') {
buildStatus = true;
return buildStatus;
}
}
function get_form_data (ssFormDataId) {
var ssFormData = SpreadsheetApp.openById(ssFormDataId);
SpreadsheetApp.setActiveSpreadsheet(ssFormData);
var sheetFormData = ssFormData.getSheets()[0];
var rangeFormData = sheetFormData.getDataRange();
var valuesFormData = rangeFormData.getValues();
return valuesFormData;
}
As an alternative, you could create the forms, and intentionally not link them to a spreadsheet, then have some code that looped through every form, and extracted the data. You'd probably want to put the forms into their own folder.
Or, you'd need to build a form with Apps Script HTML Service, embed it into a Apps Script Gadget in a Google Site, and have everyone fill out the form from Sites.
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");
}
}