How to have onFormSubmit(e) and onEdit(e) together nested - javascript

I want onFormSubmit(e) to be my main function trigger and within that I want onEdit(e) to be nested. Basically, no matter, the trigger will run onFormSubmit but it will do others within the onEdit if there is any edit, if there isn't then it will do something else.
I can't see to understand and make it work.
My script triggers shows onFormSubmit as the only function and onEdit is not in the dropdown.
function onFormSubmit(e){
ScriptApp.newTrigger("onEdit").timeBased().after(60000).create();
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet().getRange('SpeedVSD');
var sheet = ss.getSheetByName("Responses 1");
var row = ss.range.getRow();
var col = ss.range.getColumn();
if (col >= ss.getColumn() && col <= ss.getLastColumn() && row >= ss.getRow() && row <= ss.getLastRow()){
console.log("You edited a Cell within Range");
}
}
edit: Managed to get my lastRow value. However, I am still looking to get a command that can get the lastRow value for all the columns instead of manually doing it.
edit: Using a FOR Loop helps with collating the values.
//This is to get the Last Row on Column 2 value.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
for(var i = 1; i <= sheets.getLastColumn(); i++){
var myID = sheets.getRange(row, i).getValue();
}
console.log("Row Number: "+row);
console.log("Content of last Row: "+myID);```

If you want the onEdit() to run always, you just create it as a separate function. then you can call it from the onFormSubmit(), like this:
function onFormSubmit(e){
//does something you need...
onEdit();
}
onEdit(e){
//do the onEdit code...
}
The only problem with this is that the event e for onFormSubmit() is different than the one for onEdit(), so working with events might not be the best idea. However, calling one function from the other would fun just like with any other function.

function onFormSubmit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
var myIDCol2 = 2;
var myIDCol3 = 3;
var myID2 = sheets.getRange(row, myIDCol2).getValue();
var myID3 = sheets.getRange(row, myIDCol3).getValue();
console.log("Speed Before Trigger Value: "+myID2);
console.log("Voltage Before Trigger Value: "+myID3);
ScriptApp.newTrigger("responsechange").timeBased().after(60000).create();
}
function responsechange(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheetByName('FIRST');
var row = sheets.getLastRow();
var myIDCol2 = 2;
var myIDCol3 = 3;
/*for(var i = 1; i <= sheets.getLastColumn(); i++){
console.log("Content of last Row: "+myID);
}*/
var myID2 = sheets.getRange(row, myIDCol2).getValue();
var myID3 = sheets.getRange(row, myIDCol3).getValue();
var template1 = HtmlService.createTemplateFromFile("speed1");
var template2 = HtmlService.createTemplateFromFile("voltage");
template1.speed1 = myID2;
template2.voltage = myID3;
console.log("Speed After Trigger Value: "+myID2);
console.log("Voltage After Trigger Value: "+myID3);
if((myID2 >=100) || (myID2 <= 50)){
MailApp.sendEmail("someone#gmail.com","Out of Range Notification Speed","",{htmlBody: template1.evaluate().getContent()});
}
if((myID3 >=100) || (myID3 <= 50)){
MailApp.sendEmail("someone#gmail.com","Out of Range Notification Voltage","",{htmlBody: template2.evaluate().getContent()});
}
}
With this, I managed make it work whereby on form submit, lets say the values are below 50 and above 100, it will trigger an email after the time-based trigger. I also tried within the time-based trigger, I edited the values to be within the range and it did not send an email. However, the only problems now is, if there are many triggers, it will stop the trigger by saying
This script has too many triggers. Triggers must be deleted from the script before more can be added.
But on the bright side, I managed to get the last value submitted to have it checked if it was edited or not.

Related

creating a custom function between 2 different spreadsheets in apps script

i am trying to make a function that take a column from spreadsheet A and paste it as a row on spreadsheet B (transposed), the function works as expected from the apps script editor, but when i try to call it from it's linked spreadsheet i get this error: "Exception: You do not have permission to call SpreadsheetApp.openByUrl. Required permissions: https://www.googleapis.com/auth/spreadsheets (line 6)."
this is the code for the function:
function transposeColumn(colNum) {
var srcSheet = SpreadsheetApp.openByUrl("mySRCsheetID");
srcLastRow = srcSheet.getLastRow();
srcSheet = srcSheet.getDataRange().getValues();
console.log(srcSheet[0][colNum - 1]);
dataToCopy = [];
for (var i = 0; i < srcLastRow; i++) {
if (srcSheet[i][colNum - 1] == '') {
break;
} else {
dataToCopy[i] = srcSheet[i][colNum - 1];
}
}
console.log(dataToCopy);
dataLength = dataToCopy.length;
console.log(dataLength)
var destSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var destCell = destSheet.getActiveCell();
var cellCol = destCell.getRow();
var cellRow = destCell.getColumn();
for (var i = 0; i < dataLength; i++) {
destSheet.getRange(cellRow, cellCol).setValue(dataToCopy[i]);
cellCol++;
}
}
i need this function to run properly when i call it from the destination spreadsheet.
An example of simplest solution is here:
function onOpen() {
SpreadsheetApp.getUi().createMenu('⚙ Scripts')
.addItem('Get column', 'get_column')
.addToUi();
}
function get_column() {
var s_src = SpreadsheetApp.openByUrl("your_url");
var col = s_src.getRange("A1:A").getValues().flat();
var row = SpreadsheetApp.getActiveSheet().getRange(1,1,1,col.length);
row.setValues([col]);
}
After reload you will get the menu
Perhaps you need to run the function onOpen() from Script Editor first time to get permissions.
This script copies column A from source spreadsheet and paste it as a row 1 on active sheet.
If you need to get another columns (by its index or letter) it can be done. Let me know. For example you can put the index (or letter) of required column in current cell and script can read the number (or letter) from current cell. Or you can show a prompt message to input the index (or letter) of required column.

Google Script createEvent() function suddenly stopped working

Finally I was able to create function that will automatically update event in a calendar. I tested it and it worked perfectly; it will add new event in the calendar, and when user edits it, it will delete previous event and create new event along with new ID.
The next day however, when I tested it again, it doesn't work, I checked all functions in the code.gs, only this function has problem.
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('XXXXXXXXXXXXXXXXXXX#group.calendar.google.com');
var numValues = 0;
for (var i = 0; i < values.length; i++) {
if (values[i][0].length > 0) {
if (values[i][12] == undefined) {
var newEvent = calendar.createEvent("booked", request.date, request.endTime);
var newEventId = newEvent.getId().split('#')[0];
//mark as entered, enter ID
sheet.getRange(i+2,13).setValue('y');
sheet.getRange(i+2,12).setValue(newEventId);
}
else if (values[i][12] == 'y') {
var eventEditId = calendar.getEventSeriesById(values[i][11]);
eventEditId.deleteEventSeries();
var newEvent = calendar.createEvent("booked", request.date, request.endTime);
var newEventId = newEvent.getId().split('#')[0];;
//mark as entered, enter ID
sheet.getRange(i+2,13).setValue('y');
sheet.getRange(i+2,12).setValue(newEventId);
}
}
numValues++;
}
};
I also checked the calendar settings and stuffs, and made sure that I was logged into the admin account. Any help is greatly appreciated, thanks in advance.
I simply changed "undefined" to simply a null string ' ' , it works again. But again, for some reason i am curious why it worked last time with "undefined" command

How to copy and set a row of data into another sheet if a string condition is met in a column

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:

Google Script - Sending Email from drop-down

I am trying to fix a code I found online. My goal is that once the Summary tab, column I is edited with the drop-down "approved" for the sheet to send an email to the person on the name in column D.
The email is found in the range tab though. This is what I have so far...
var admin_email='taniapeche#gmail.com';
function triggerOnEdit(e)
{
sendEmailOnApproval(e);
}
function checkStatusIsApproved(e)
{ var sheet = SpreadsheetApp.getActive().getSheetByName('Summary');
var range = e.range;
if(range.getColumn() <= 9 &&
range.getLastColumn() >=9 )
{
var edited_row = range.getRow();
var status = SpreadsheetApp.getActiveSheet().getSheetName('Summary').getRange(edited_row,9).getValue();
if(status == 'Approved')
{
return edited_row;
}
}
return 0;
}
function sendEmailOnApproval(e)
{ var sheet = SpreadsheetApp.getActive().getSheetByName('Range');
var approved_row = checkStatusIsApproved(e);
if(approved_row <= 0)
{
return;
}
sendEmailByRow(approved_row);
}
function sendEmailByRow(row)
{
var values = SpreadsheetApp.getActiveSheet().getSheetName('Range').getRange(row,1,row,5).getValues();
var row_values = values[0];
var mail = composeApprovedEmail(row_values);
//SpreadsheetApp.getUi().alert(" subject is "+mail.subject+"\n message "+mail.message);
MailApp.sendEmail(admin_email,mail.subject,mail.message);
}
function composeApprovedEmail(row_values)
{
var first_name = row_values[1];
var last_name = row_values[2];
var email = row_values[3];
var message = "The following mileage is approved: "+first_name+" "+last_name+
" email "+email;
var subject = "Mileage approved "+first_name+" "+last_name
return({message:message,subject:subject});
}
This is how to sheet looks:
https://docs.google.com/spreadsheets/d/1lWORvuwAHducEIiL-VVidJ-wjujE344udPbWCZpE1kw/edit?usp=sharing
Thanks for the help :)
First of all, because you want the script to send an email (an action which requires your authorization), you have to install the edit trigger, either manually or programmatically. If you do it programmatically, you can install the trigger by running this function once:
function createTriggerOnEdit(e) {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("sendEmailOnApproval")
.forSpreadsheet(ss)
.onEdit()
.create();
}
As a result of this, the function sendEmailOnApproval will fire every time the spreadsheet is edited. This function could be something along the following lines (check inline comments for detailed explanation):
function sendEmailOnApproval(e) {
// Get the edited range and sheet using the event object:
var range = e.range;
var editedSheet = range.getSheet();
var textToSearch = "Approved"; // Set which value will cause the email to be sent
// Check that edited cell is in column I, its value is "Approved" and its sheet is "Summary":
if (range.getColumn() === 9 && range.getValue() === textToSearch &&
editedSheet.getName() === "Summary") {
var rowIndex = range.getRow(); // Get index of the edited row
var name = editedSheet.getRange(rowIndex, 4).getValue(); // Get corresponding name in column D
var rangeValues = e.source.getSheetByName("Range").getDataRange().getValues(); // Get values in sheet "Range"
// Iterate through the rows in "Range", looking for the name retrieved from sheet "Summary"
for (var i = 0; i < rangeValues.length; i++) {
var rowValues = rangeValues[i];
if (name === rowValues[0]) { // Check if name matches the one in column D from "Summary"
var mail = composeApprovedEmail(rowValues); // Compose email (your function)
MailApp.sendEmail(admin_email, mail.subject, mail.message); // Send email
return; // End execution so that the script stops iterating through the rows in "Range"
}
}
}
}
Notes:
The function composeApprovedEmail is called in this sample. It's the same as the one you provided. The rest of functions you provided are not used.
Reference:
Installable Triggers
Event Objects: Edit

Google Apps Script, spreadsheet, taking too long to run

I'm using an onEdit() function that checks which cell in which sheet has been changed to run the appropriated routine.
When the changed cell is in sheet1 and is not the I3 it should run a simple routine, but it is taking too long.
Here is the code:
if (sheet === 'sheet1'){
if (changedCell != 'I3') {
var row = e.source.getActiveRange().getRow();
var cont = row-6;
var column = e.source.getActiveRange().getColumn();
var Relatorio = ss.getSheetByName("RELATÓRIOS_ACOMPANHAMENTO");
var edit = Relatorio.getRange(row, column);
var coluna = Relatorio.getRange(5, column).getValue();
var linha = Relatorio.getRange(row, 15).getValue();
var baseAcom = ss.getSheetByName("EVENTOS_PARTICIPANTES");
var editbase = baseAcom.getRange(linha, coluna);
edit.copyTo(editbase, {contentsOnly: true});
}
}
When I check the spreadsheet, it does what i want to do very fast, but it stays showing the calculating formulas bar for almost 1 min, and I can't perform any other functions until it ends.
Is there a way for me to speed it up?

Categories