How to reduce execution time of this script (Google app script timeout) - javascript

I have this piece of script.
It filter a range by a criteria,
then It copy values that respect criteria in a specific sheet
then It deletes all the row in the original sheet that respect the criteria.
So that If my range contains more than 1000 rows, It's said to me error: Google app script timeout.
I put my code here, can You help me to get a better performance about execution time of this script?
function trasferisciDati() {
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Inserisci il mese dei dati da esportare', '(Esempio: agosto (tutto minuscolo))', ui.ButtonSet.OK_CANCEL);
var inizioTRASFERISCIVALORI = Utilities.formatDate(new Date(), "CET", "HH:mm:ss.SSS");
if (response.getSelectedButton() == ui.Button.OK) {
//get filtered range and set values to the new range
var description = ui.prompt('Inserisci una descrizione per questa esportazione', 'apparirà come tag dell\'esportrazione', ui.ButtonSet.OK_CANCEL);
var sourceData = SpreadsheetApp.openById("1XkYhjdQfgU7mVCR7E8mfZsf292I-cJ16PnpCimnd1v8").getSheetByName("Prova");
var destinationData = SpreadsheetApp.openById("1cdXMqqBwgWK5nCQUtAP_TyIIDOHksS7wWvSG4jRu658").getSheetByName("Prova");
var lastRow = sourceData.getLastRow();
var data = sourceData.getRange(1, 1, lastRow, 1).getValues();
var chiave = response.getResponseText();
for(var i=0;i<data.length;i++)
{
if (data[i][0] == chiave) {
var filteredRow = sourceData.getRange(i+1,1,1,5).getValues();
destinationData.appendRow(filteredRow[0]);
}
}
//number of records of the filtered range
var lastRow = destinationData.getLastRow();
var data = destinationData.getRange(1, 6, lastRow, 1).getValues();
var loop = 0
for(var i=0;i<data.length;i++)
{
if(!data[i][0])
{
var loop = loop + 1
}
}
Logger.log(Utilities.formatString('%1.0f', Math.floor(loop)))
//appendi timestamp al rigo ed eventuale descrizione aggiuntiva inserita dall'utente
var lastRow = destinationData.getLastRow();
var data = destinationData.getRange(1, 6, lastRow, 1).getValues();
var timestamp = Utilities.formatDate(new Date(), "CET", "dd/MM/YYYY HH.mm.ss")
for(var i=0;i<data.length;i++)
{
if(!data[i][0])
{
destinationData.getRange(i+1,6).setValue(timestamp)
destinationData.getRange(i+1,7).setValue(description.getResponseText())
}
}
//cancella l'intervallo originale
var maxRows = sourceData.getMaxRows();
var data = sourceData.getRange(1, 1, maxRows, 1).getValues();
for(var i=data.length; i>=0;i--)
{
if (data[i] == chiave) {
sourceData.deleteRow(i+1)
}
}
var fineTRASFERISCIVALORI = Utilities.formatDate(new Date(), "CET", "HH:mm:ss.SSS");
var inTime=inizioTRASFERISCIVALORI.split(":");
var outTime= fineTRASFERISCIVALORI.split(":");
var hr = outTime[0] - inTime[0];
var min = ((outTime[1] - inTime[1])+hr*60)%60;
var sec = ((outTime[2] - inTime[2])+min*60)%60;
var duration = Utilities.formatString('%2.0f', Math.floor(hr)) + 'h ' + Utilities.formatString('%2.0f', Math.floor(min)) + 'm ' + Utilities.formatString('%2.0f', sec) + 's';
ui.alert('Trasferite '+ Utilities.formatString('%1.0f', Math.floor(loop)) +' righe in '+ duration, ui.ButtonSet.OK)
} else if (response.getSelectedButton() == ui.Button.CANCEL) {
SpreadsheetApp.getUi().alert('L\'utente ha annullato l\'operazione');
} else {
SpreadsheetApp.getUi().alert('L\'utente ha chiuso la finestra di dialogo');
}
}

You might try this:
var data = sourceData.getRange(1, 1, lastRow, 5).getValues();
var chiave = response.getResponseText();
for(var i=0;i<data.length;i++)
{
if (data[i][0] == chiave)
{
//var filteredRow = sourceData.getRange(i+1,1,1,5).getValues();
destinationData.appendRow(data[i]);
}
}
And you might consider the same thing on your destination data.

Related

setValue function skipping rows instead of choosing current in for loop

I have this code in Google Apps Script that is linked to a Google Sheet:
function sendReminders() {
var sheet = SpreadsheetApp.openById('1IvXctYLXMKrSYPPSuMg_4_AQopemHPSnLHmQQgBDqH8').getSheetByName('ÉVALUATION');
var startRow = 2;
var numRows = sheet.getLastRow();
var numColumns = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows, numColumns);
var data = dataRange.getValues();
for (var i in data) {
var row = data[i];
var email = row[4];
var ccEmail = row[5];
var customId = row[1];
var dueDate = Utilities.formatDate(new Date(row[9]), Session.getScriptTimeZone(), "yyyy-MM-dd");
var message = 'Votre E&A est dûe pour la date suivante : ' + dueDate + '. Merci de la compléter en cliquant sur le lien suivant : https://form.jotform.com/221156384847058?customId3=' + customId;
var emailSent = row[12];
var value = Utilities.formatDate(new Date(row[10]), Session.getScriptTimeZone(), "yyyy-MM-dd");
var today = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd");
if (value == today && emailSent != 1) {
var subject = 'Rappel - Enquête & Analyse';
MailApp.sendEmail(email, subject, message, { cc: ccEmail });
sheet.getRange((startRow + i), 13).setValue(1);
SpreadsheetApp.flush();
}
}
}
The script is supposed to send reminder emails. Everything works well, except this one line:
sheet.getRange((startRow + i), 13).setValue(1);
This line should add the value of 1 to a specific cell in the Google Sheet, in the current row the for loop is at.
However, instead of adding the value to the current row, it skips rows and adds the value to some other row. In some cases, there's a difference of 18 rows, and in others, 198 rows.
Here is the Google Sheet link for reference.
I noticed some issues in your sheet and script.
In your sample sheet, you have values on M22, M27 and M210. The function sheet.getLastRow() will include those values and your last row will be 210.
If you print the value of data, there is an extra empty array.
If you try to print startRow + i, the values are 22, 23, 24...etc. It just appends the value of startRow and i and not doing the arithmetic operation sum.
Solution:
Remove the unnecessary data or clean your sheet so that the value of numRows will become 12.
Since you skip 1 row, you should also deduct 1 row to numRow. Simple add -1 to numRows in your getRange().
Use the parseInt() method to variable i in sheet.getRange((startRow + i), 13).setValue(1);.
Your code should look like this:
function sendReminders() {
var sheet = SpreadsheetApp.openById('1IvXctYLXMKrSYPPSuMg_4_AQopemHPSnLHmQQgBDqH8').getSheetByName('ÉVALUATION');
var startRow = 2;
var numRows = sheet.getLastRow();
var numColumns = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows-1, numColumns);
var data = dataRange.getValues();
for (var i in data) {
var row = data[i];
var email = row[4];
var ccEmail = row[5];
var customId = row[1];
var dueDate = Utilities.formatDate(new Date(row[9]), Session.getScriptTimeZone(), "yyyy-MM-dd");
var message = 'Votre E&A est dûe pour la date suivante : ' + dueDate + '. Merci de la compléter en cliquant sur le lien suivant : https://form.jotform.com/221156384847058?customId3=' + customId;
var emailSent = row[12];
var value = Utilities.formatDate(new Date(row[10]), Session.getScriptTimeZone(), "yyyy-MM-dd");
var today = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd");
if (value == today && emailSent != 1) {
var subject = 'Rappel - Enquête & Analyse';
MailApp.sendEmail(email, subject, message, { cc: ccEmail });
sheet.getRange((startRow + parseInt(i)), 13).setValue(1);
SpreadsheetApp.flush();
}
}
}
Sample:
Note: I adjusted the Reminder Date values to my current date so that the script will work.
Output:
Reference:
parseInt()
Try it this way:
function sendReminders() {
const ss = SpreadsheetApp.openById('1IvXctYLXMKrSYPPSuMg_4_AQopemHPSnLHmQQgBDqH8');
var sh = ss.getSheetByName('ÉVALUATION');
var startRow = 2;
var dataRange = sh.getRange(startRow, 1, sh.getLastRow() - 1, sh.getLastColumn());
var vs = dataRange.getValues();
vs.forEach((r, i) => {
var email = r[4];
var ccEmail = r[5];
var customId = r[1];
var dueDate = Utilities.formatDate(new Date(r[9]), Session.getScriptTimeZone(), "yyyy-MM-dd");
var message = 'Votre E&A est dûe pour la date suivante : ' + dueDate + '. Merci de la compléter en cliquant sur le lien suivant : https://form.jotform.com/221156384847058?customId3=' + customId;
var emailSent = r[12];
var value = Utilities.formatDate(new Date(r[10]), Session.getScriptTimeZone(), "yyyy-MM-dd");
var today = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd");
if (value == today && emailSent != 1) {
var subject = 'Rappel - Enquête & Analyse';
MailApp.sendEmail(email, subject, message, { cc: ccEmail });
sh.getRange(startRow + i, 13).setValue(1);
}
});
}

Google sheets - How to get row index of a column, based on the index of edit URL from the same row?

I am coding a room booking system using combination of Google forms and Google calendar.
When there is a new booking order:
An event will be automatically created on the selected calendar.
An edit response URL will also be generated automatically and put in column 10 of the spreadsheet in the same row where the form answer was inserted.
// This is the function to generate the edit URL (which works perfectly).
function getEditUrl(request) {
var formRes = FormApp.openById('XXXXXXXXXXXXXXXXXXXXXXXXXXXX');
var sheetRes = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('YYYYYYYYYY');
var data = sheetRes.getDataRange().getValues();
var urlCol = 10;
var responses = formRes.getResponses();
var timestamps = [],
urls = [],
resultUrls = [];
for (var i = 0; i < responses.length; i++) {
timestamps.push(responses[i].getTimestamp().setMilliseconds(0));
urls.push(responses[i].getEditResponseUrl());
}
for (var j = 1; j < data.length; j++) {
resultUrls.push([data[j][0] ? urls[timestamps.indexOf(data[j][0].setMilliseconds(0))] : '']);
}
sheetRes.getRange(2, urlCol, resultUrls.length).setValues(resultUrls);
};
However, problem occurs when there are more than 2 orders; as the next order will delete the calendar event from the previous order.
// This is the function to update the calendar event.
function updateCalendar(request) {
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(2, 1, lastRow, 13);
var values = range.getDisplayValues();
var calendar = CalendarApp.getCalendarById('XXXXXXXXXXXXXXXXXXXXXXXX#group.calendar.google.com');
for (var i = 0; i < responses.length; i++) {
getConflicts(request);
if (request.eventConflict == "conflict") {
sheet.getRange(lastRow, 11).setValue("conflict");
break;
} else if (request.eventConflict == "approve") {
var newEvent = calendar.createEvent("booked", request.date, request.endTime);
var newEventId = newEvent.getId().split('#')[0];
sheet.getRange(lastRow, 11).setValue("approve");
sheet.getRange(lastRow, 12).setValue(newEventId);
break;
}
}
for (var j = 1; j < values.length; j++) {
if (values[j][10] == "approve") {
var eventEditId = calendar.getEventSeriesById(values[j][11]);
eventEditId.deleteEventSeries();
sheet.getRange(j + 2, 11).setValue("");
getConflicts(request);
if (request.eventConflict == "approve" && values[j][10].length > 1) {
var newEvent = calendar.createEvent("booked", request.date, request.endTime);
var newEventId = newEvent.getId().split('#')[0];
sheet.getRange(j + 2, 11).setValue("approve");
sheet.getRange(j + 2, 12).setValue(newEventId);
break;
} else {
sheet.getRange(j + 2, 11).setValue("conflict");
break;
}
}
}
};
My questions:
How to make sure that when respondent edits his/her own response, it will always update event from the same column as the edit URL? --> I have separate function that will send edit URL to respondents
When there is more than two submission, the 3rd submission will delete event of the 2nd one. (I am sure the issue is on the updateCalendar() function).
I have been struggling so much for the past few days trying to figure out the best way to come up with best loop method. Any help / response is greatly appreciated.
EDIT:
This is the column description of the sheets (separated with |):
Timestamp
Email Address
name
Check-in date
Check-out date
Room
No. of people
total day
total
edit URL
Event Conflict
Event ID
This is the function to get event conflicts in the calendar:
function getConflicts(request){
var conflicts = request.calendar.getEvents(request.date, request.endTime);
if (conflicts.length > 0) {
request.eventConflict = "conflict";
} else {
request.eventConflict = "approve"
}
};
And this is the main function that will be triggered on formsubmit:
function main(){
var request = new Submission(lastRow);
getEndTime(request);
draftEmail(request);
updateCalendar(request);
};
This is the screenshot of the sheet
Finally I found one way to retrieve the edited row by using e.range method. So basically I created another sheet inside the same spreadsheet. When there is a new submission, it will automatically copy the new submission to the second sheet. And when there is an edited submission, it will go through the copy sheet to find the edited row, and then edit it (as well as the calendar). Credit to Tedinoz
function updateCalendarTwo(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var responsename = "AAAAAAAAAAAAAAA"
var copyname = "BBBBBBBBBBBB";
var responsesheet = ss.getSheetByName(responsename);
var copysheet = ss.getSheetByName(copyname);
var calendar = CalendarApp.getCalendarById('CCCCCCCCCCCCCCCCCCCC');
// columns on copysheet
var checkInCol = 4;
var checkOutCol = 5;
var roomNumCol = 6;
var appCol = 11
var eventIDCol = 12;
var revCol = 14;
var response = e.range;
var rRow = response.getRow()
var rLC = responsesheet.getLastColumn();
var cLC = copysheet.getLastColumn();
var rLR = responsesheet.getLastRow();
var cLR = copysheet.getLastRow();
if (rLR > cLR){
var resprange = responsesheet.getRange(rLR,1,1,rLC);
var respdata = resprange.getValues();
copysheet.appendRow(respdata[0]);
var eventTitle = copysheet.getRange(rRow,roomNumCol).getValue();
var startDate = copysheet.getRange(rRow,checkInCol).getValue();
var endDate = copysheet.getRange(rRow,checkOutCol).getValue().getTime()+ 24 * 60 * 60 * 1000;
var conflicts = calendar.getEvents(new Date(startDate), new Date(endDate));
if (conflicts.length < 1) {
var event = calendar.createAllDayEvent(eventTitle, new Date(startDate), new Date(endDate));
var eventID = event.getId().split('#')[0];
copysheet.getRange(rRow,appCol).setValue("approve");
copysheet.getRange(rRow,eventIDCol).setValue(eventID);
} else {
copysheet.getRange(rRow,appCol).setValue("conflict");
}
} else {
var resprange = responsesheet.getRange(rRow,1,1,9);
var respdata = resprange.getValues();
var copyrespRange = copysheet.getRange(rRow,1,1,9);
copyrespRange.setValues(respdata);
var respAppRange = copysheet.getRange(rRow,appCol);
var respApp = respAppRange.getValue();
if (respApp == 'conflict') {
var eventTitle = copysheet.getRange(rRow,roomNumCol).getValue();
var startDate = copysheet.getRange(rRow,checkInCol).getValue();
var endDate = copysheet.getRange(rRow,checkOutCol).getValue().getTime()+ 24 * 60 * 60 * 1000;
var conflicts = calendar.getEvents(new Date(startDate), new Date(endDate));
if (conflicts.length < 1) {
var editedEvent = calendar.createAllDayEvent(eventTitle, new Date(startDate), new Date(endDate));
var editedEventID = editedEvent.getId().split('#')[0];;
copysheet.getRange(rRow,appCol).setValue("edited");
copysheet.getRange(rRow,eventIDCol).setValue(editedEventID);
} else {
copysheet.getRange(rRow,appCol).setValue("conflict");
};
} else {
var eventEditId = copysheet.getRange(rRow,eventIDCol).getDisplayValue();
var editedEvent = calendar.getEventSeriesById(eventEditId);
editedEvent.deleteEventSeries();
var eventTitle = copysheet.getRange(rRow,roomNumCol).getValue();
var startDate = copysheet.getRange(rRow,checkInCol).getValue();
var endDate = copysheet.getRange(rRow,checkOutCol).getValue().getTime()+ 24 * 60 * 60 * 1000;
var conflicts = calendar.getEvents(new Date(startDate), new Date(endDate));
if (conflicts.length < 1) {
var editedEvent = calendar.createAllDayEvent(eventTitle, new Date(startDate), new Date(endDate));
var editedEventID = editedEvent.getId().split('#')[0];;
copysheet.getRange(rRow,appCol).setValue("edited");
copysheet.getRange(rRow,eventIDCol).setValue(editedEventID);
} else {
copysheet.getRange(rRow,appCol).setValue("conflict");
};
};
var revRange = copysheet.getRange(rRow,revCol);
var revOldValue = revRange.getValue();
if (revOldValue == null || revOldValue == ""){
revOldValue = 0;
}
var revNewValue = revOldValue+1;
revRange.setValue(revNewValue);
}
}

JDBC connection in Google Sheet

I am using the script made by Mike Seekwell [Link] for connecting a MySQL database to a Sheet, and it works.
My problem is that I need it to run always from the first cell of the first sheet, while actually it can run from every active cell of every active sheet.
How can I modify this thing?
Here is the script:
/**
* #OnlyCurrentDoc
*/
var MAXROWS = 1000
var SEEKWELL_J_SHORT_DATES = { day: "yyyy-MM-dd", month: "yyyy-MM", year: "yyyy", dayNum: "dd", monthNum: "MM", yearNum: "yyyy", week: "W" }
var SEEKWELL_J_TIMEZONE = "UTC"
var HOST = '//host'
var PORT = '//port'
var USERNAME = '//username'
var PASSWORD = '//password'
var DATABASE = '/database'
var DB_TYPE = 'mysql'
function goToSheet(sheetName) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName(sheetName));
};
function runSql(query, options) {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheet = doc.getActiveSheet();
var sheetName = sheet.getName();
var cell = doc.getActiveSheet().getActiveCell();
var activeCellRow = cell.getRow();
var activeCellCol = cell.getColumn();
try {
var fullConnectionString = 'jdbc:' + DB_TYPE + '://' + HOST + ':' + PORT
var conn = Jdbc.getConnection(fullConnectionString, USERNAME, PASSWORD);
console.log('query :', query)
var stmt = conn.createStatement();
stmt.execute('USE ' + DATABASE);
var start = new Date();
var stmt = conn.createStatement();
stmt.setMaxRows(MAXROWS);
var rs = stmt.executeQuery(query);
} catch (e) {
console.log(e, e.lineNumber);
Browser.msgBox(e);
return false
}
var results = [];
cols = rs.getMetaData();
console.log("cols", cols)
var colNames = [];
var colTypes = {};
for (i = 1; i <= cols.getColumnCount(); i++) {
var colName = cols.getColumnLabel(i)
colTypes[colName] = { type: cols.getColumnTypeName(i), loc: i }
colNames.push(colName);
}
var rowCount = 1;
results.push(colNames);
while (rs.next()) {
curRow = rs.getMetaData();
rowData = [];
for (i = 1; i <= curRow.getColumnCount(); i++) {
rowData.push(rs.getString(i));
}
results.push(rowData);
rowCount++;
}
rs.close();
stmt.close();
conn.close();
console.log('results', results)
var colCount = results[0].length
var rowCount = results.length
var comment = "Updated on: " + (new Date()) + "\n" + "Query:\n" + query
if (options.omitColumnNames) {
results = results.slice(1)
rowCount -= 1
}
if (options.clearColumns && sheet.getLastRow() > 0) {
var startCellRange = sheet.getRange(startCell)
sheet.getRange(startCellRange.getRow(), startCellRange.getColumn(), sheet.getLastRow(), colCount).clearContent();
}
if (options.clearSheet) {
var startCellRange = sheet.getRange(startCell)
sheet.clear({ contentsOnly: true });
}
sheet.getRange(activeCellRow, activeCellCol, rowCount, colCount).clearContent();
sheet.getRange(activeCellRow, activeCellCol, rowCount, colCount).setValues(results);
var cell = sheet.getRange(activeCellRow, activeCellCol)
cell.clearNote()
cell.setNote(comment);
sheet.setActiveRange(sheet.getRange(activeCellRow + rowCount + 1, activeCellCol))
console.log('query success!, rows = ', rowCount - 1)
}
function runSqlFromSheet() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sql = doc.getRange('query!a2').getDisplayValue();
var options = {}
Logger.log('sql;', sql)
runSql(sql, options)
}
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('SeekWell Blog')
.addItem('Run SQL', 'runSqlFromSheet')
.addToUi();
}
function launch() {
var html = HtmlService.createHtmlOutputFromFile('sidebar')
.setTitle('SeekWell');
SpreadsheetApp.getUi()
.showSidebar(html);
}
I solved the problem. Not in the most elegant way, but it is a solution...
In order to run the script always on the same sheet, I substitute two variables.
The first variable to substitute is the following one:
var sheet = doc.getActiveSheet();
With this one (so it is always the first tab)
var sheet = doc.getSheets()[0];
Then the following one:
var cell = doc.getActiveSheet().getActiveCell();
With this one (so it is possible to define from which cell the script has to start, in this example from A1)
var cell = sheet.getRange('A1');

Exception: Argument cannot be null: prompt Error in google Scripts

I have created a mail merge with a confirmation pop up in order to confirm the script has not been run recently, and also to double check the user intends to send emails. The script works perfectly, but annoyingly I receive the following error when run:
Stating; Exception: Argument cannot be null: prompt
I would like to get rid of this if possible. I attach my code.
//Creates a functional log of how many emails are sent and to how many branches
function confirmationWindow(){
var numberSent = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Validations').getRange('D3').getValue();
var numberOfVios = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Validations').getRange('D2').getValue();
var ui = SpreadsheetApp.getUi();
var ui = SpreadsheetApp.getUi();
ui.alert(
'You have succesfully sent ' + numberOfVios + ' violations, to ' + numberSent + ' branches.',)
}
function saveData() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Log');
var date = new Date()
var user = Session.getActiveUser().getEmail();
var range = ss.getRange("A:B")
var numberSent = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Validations').getRange('D2').getValue();
var branchNumber = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Validations').getRange('D3').getValue();
ss.appendRow([date,user,numberSent,branchNumber]);
}
var EMAIL_SENT = 'True';
function sendEmails() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Output');
var sheetI= SpreadsheetApp.getActive().getSheetByName('Input');
var sheetC = SpreadsheetApp.getActive().getSheetByName('Control');
var emailNum = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Validations').getRange('D3').getValue();
var startRow = 2;
var numRows = emailNum;
var dataRange = sheet.getRange(startRow, 1, numRows, 6);
sheetI.setTabColor("ff0000");
saveData()
var data = dataRange.getValues();
for (var i in data) {
var row = data[i];
var emailAddress = row[3];
var message = row[5] + "\n\nT\n\nT\n\nT";
var message = message.replace(/\n/g, '<br>');
var subject = row[4];
MailApp.sendEmail(emailAddress, subject, message,{htmlBody:message});
sheet.getRange(startRow + i - 18, 8).setValue(EMAIL_SENT);
sheetC.getRange(startRow + i - 18, 3).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
confirmationWindow()
}
function recentSend() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Log');
var lastR = sheet.getLastRow();
var recentRun = sheet.getRange('A' + lastR).getValue();
if(lastR=1){var recentlySent = 'False'}
var today = new Date().valueOf()
var recentDate = recentRun
var sec = 1000;
var min = 60 * sec;
var hour = 60 * min;
var day = 24 * hour;
var difference = today - recentDate
var hourDifference =Math.floor(difference%day/hour);
if (hourDifference > '12'){var recentlySent = 'False'}
else {var recentlySent = 'True'}
return(recentlySent)
}
function recentlySentTrue(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Log');
var lastR = sheet.getLastRow();
var recentUser = sheet.getRange('B' + lastR).getValue();
var recentQuant = sheet.getRange('C' + lastR).getValue();
var recentT = sheet.getRange('A' + lastR).getValue();
var recentSendLog = recentT.toString();
var recentTime = recentSendLog.slice(16,21)
var recentDate = recentSendLog.slice(0,11)
var ui = SpreadsheetApp.getUi();
var result = ui.alert(
'Are you sure you wish to send?',
'The user, ' + recentUser + ' ,recently sent ' + recentQuant + ' emails, at ' + recentTime + ' on ' + recentDate,
ui.ButtonSet.YES_NO);
if (result == ui.Button.YES) {
ui.alert(recentlySentFalse());
}
else {
}
}
function recentlySentFalse(){
var ui = SpreadsheetApp.getUi();
var ui = SpreadsheetApp.getUi();
var result = ui.alert(
'Are you Sure you wish to send?',
'Are you sure you want to send these violations?',
ui.ButtonSet.YES_NO);
if (result == ui.Button.YES) {
ui.alert(sendEmails());
} else {
}
}
function confirm(){
var recentlySent = recentSend();
if (recentlySent == 'True'){
recentlySentTrue()
}
else{recentlySentFalse()
}
}
Any help would be great.
Explanation:
Your ui.alert() calls that have function arguments such as recentlySentFalse() are not valid, since the functions do not have return statements, hence they return the default value of null. ui.alert() calls need at least a prompt message.
Solution 1:
Put the function call after the UI alert message:
if (result == ui.Button.YES) {
ui.alert('Sending message...');
recentlySentFalse();
}
Solution 2:
If you do not want excessive alerts, just remove ui.alert and call the function immediately.
if (result == ui.Button.YES) {
recentlySentFalse();
}
References:
Class UI | Apps Script

How can I optimize with an array?

I'm starting to learn about google app script with JavaScript.
I wrote this code, but it is really slow and executing the function takes too long. I think this isn't the best way to do the function.
Is there any option/way (array), to make it faster or in other way to reduce to the time waiting?
All I wish to do is to insert "today's date", when a column cell value is set true, in another cell column.
function onEdit() {
sConfDate();
}
function sConfDate(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheetByName("Data");
var dataRange = dataSheet.getRange(9, 1, dataSheet.getLastRow(), 43);
var data = dataRange.getValues();
var d = new Date();
var dd = d.getDate();
var mm = d.getMonth() +1;
var yyyy = d.getFullYear();
var date = dd + "/" + mm + "/" + yyyy;
var needSay = 'SUC';
var needSay2 = '-';
for(var i = 0; i < data.length; i++){
//row items
var values = data[i];
//column items
for(var j = 0; j < values.length; j++){
var row = values[j];
var checkRow = row;
//Logger.log(checkRow);
if(checkRow === needSay && checkRow === needSay2){
dataSheet.getRange(9 + i, 43).setValue(date);
};
};
};
}
Perhaps this is what you had in mind:
function sConfDate(){
var ss=SpreadsheetApp.getActive();
var dataSheet=ss.getSheetByName("Data");
var dataRange=dataSheet.getRange(9, 1, dataSheet.getLastRow()-8, 43);
var data=dataRange.getValues();
var datacol43=dataSheet.getRange(9,43,dataSheet.getLastRow()-8,1).getValues();
var date=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "dd/MM/yyyy");
data.forEach(function(r,i){
r.forEach(function(c,j){
if(c=='SUC' || c=='-') {
datacol43[i][0]=date;
}
});
});
dataSheet.getRange(9,43,dataSheet.getLastRow()-8,1).setValues(datacol43);
}
This might actually run faster:
function sConfDate(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName("Data");
var rg=sh.getRange(9, 1, sh.getLastRow()-8, 43);
var data=rg.getValues();
var crg=sh.getRange(9,43,sh.getLastRow()-8,1);
var cdata=crg.getValues();
var date=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "dd/MM/yyyy");
for(var i=0;i<data.length;i++) {
for(var j=0;j<data[i].length;j++) {
if(data[i][j]=='SUC' || data[i][j]=='-') {
cdata[i][0]=date;
break;
}
}
}
crg.setValues(cdata);
}
Perhaps this would be better.
function sConfDate2(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName("Data");
var rg=sh.getRange(9, 1, sh.getLastRow()-8, 8);
var data=rg.getValues();
var crg=sh.getRange(9,8,sh.getLastRow()-8,1);
var cdata=crg.getValues();
var date=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "dd/MM/yyyy");
for(var i=0;i<data.length;i++) {
var row=data[i];//Im guessing this is probably what you want unless you have particular columns in mind
if(row.indexOf('SUC')!=-1 && row.indexOf('-')!=-1) {
cdata[i][0]=date;
}
}
crg.setValues(cdata);
}

Categories