Insert bounded code snippets to generated Google Spreadsheets - google-apps-script

I have a bounded script to a spreadsheet 'A' that generates a new spreadsheet 'N' for each name I have in a list in spreadsheet 'A'. I would like to add a bounded script to each spreadhsheet 'N' such as:
function onEdit() {
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var row = sh.getActiveCell().getRowIndex();
var col = sh.getActiveCell().getColumn();
Logger.log(row + " " + col);
if (row == 3 && col == 1)
{
var value = sh.getActiveCell().getValue();
if (value == "I")
{
var today = formatDate(new Date());
var newdate = new Date(today);
newdate.setDate(newdate.getDate() + 15);
var dd = newdate.getDate();
var mm = newdate.getMonth() + 1;
var y = newdate.getFullYear();
var someFormattedDate = mm + '/' + dd + '/' + y;
Logger.log(someFormattedDate);
sh.getRange(row, 3).setValue(someFormattedDate);
}
}
}
function formatDate(date)
{
return (date.getMonth() + 1) + '/' + date.getDate() + '/' + date.getFullYear();
}
I have tried to do that by inserting formulas but the TODAY() function always updates the cell.
Any ideas? Is it possible to add bounded snippet of code to a google spreadsheet created programmatically with google apps scripts?
Thank you for your help.

I found what I was looking for with SriptApp Class with the SpreadsheetTriggerBuilder

Related

how to print the value before it was changed?(google script)

If the value changes while using Google Script, I want to record the change in the cell next to it. Trigger is tested, but only the value after the change is saved, not the value before the change. Where do I need to fix to get the value before the change?
function onEdit1()
{
var sheet = SpreadsheetApp.getActiveSheet();
if (sheet.getName() == "sheet1") //"order data" is the name of the sheet where you want to run this script.
{
var actRng = sheet.getActiveRange();
var editColumn = actRng.getColumn();
var rowIndex = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var aCol = headers[0].indexOf("A") + 1;
var usdCol = headers[0].indexOf("USD") + 1;
var rmbCol = headers[0].indexOf("RMB") + 1;
var changedData = sheet.getRange(rowIndex, usdCol).getValues();
var logData = sheet.getRange(rowIndex, aCol).getValues();
if (aCol > 0 && rowIndex > 1 && editColumn == usdCol)
{
if (!sheet.getRange(rowIndex, aCol).isBlank())
{
sheet.getRange(rowIndex, aCol).setValue(Utilities.formatDate(new Date(), "UTC+8", "yyyy-MM-dd") + "에 " + changedData + "(으)로 변경" + "/" + logData);
}else{
logData = Utilities.formatDate(new Date(), "UTC+8", "yyyy-MM-dd") + "에 " + changedData + "(으)로 변경됨" + " / ";
// sheet.getRange(rowIndex, aCol).setValue(Utilities.formatDate(new Date(), "UTC+8", "yyyy-MM-dd") + "에 " + changedData + "(으)로 변경됨" + " / ");
}
}
}
}
To get the value of a cell before it changes you could use the on edit trigger.
If a single cell is edited and, the event object might included value and oldValue properties.
The following is a very simple example that logs the old value to the cell to the right of the edited cell.
function onEdite(e){
if(e.oldValue) e.range.offset(0,1).setValue(e.oldValue);
}
The value property will be undefined if the cell is cleared.
The oldValue property will be undefined if the cell was blank
Both properties will be undefined if multiple cells were edited (range property includes more than one cell)

Auto Send Email When Checkbox is Checked - Google Sheet

I tried the script from Auto Email Function for Google Sheets Mobile and it worked the first time. When I tried to change the variables, it does not automatically send the email, unless I run the script again, it would then update the response sheet and then clears the checkbox. Please help me with this. Kindly see my code below.
function EmailNotification(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Course_AutoEmail'); //source sheet
var columnb = sheet.getRange('I:I'); //Column with check boxes
var columnbvalue = columnb.getValues();
var notifysheet = ss.getSheetByName('Responses'); //destination sheet
var data = [];
var rownum = [];
//Condition check in B:B (or check box column); If true copy the same row to data array
for (let i = 0; i < columnbvalue.length; i++) {
if (columnbvalue[i][0] === true) {
var columnb2 = sheet.getRange('I747:I'); //row started in row 747
columnb2.setValue('false');
data.push.apply(data, sheet.getRange(i + 1, 1, 1, 20).getValues());
//Copy matched ROW numbers to rownum
rownum.push(i);
//Copy data array to destination sheet
notifysheet.getRange(notifysheet.getLastRow() + 1, 1, data.length, data[0].length).setValues(data);
var activeRow = notifysheet.getLastRow();
var name = notifysheet.getRange(activeRow, 1).getDisplayValue(); // The number is the column number in the destination "responses" sheet that you want to include in the email
var employeeID = notifysheet.getRange(activeRow, 2).getDisplayValue();
var position = notifysheet.getRange(activeRow, 3).getDisplayValue();
var team = notifysheet.getRange(activeRow, 4).getDisplayValue();
var date = notifysheet.getRange(activeRow, 10).getDisplayValue();
var rec1 = notifysheet.getRange(activeRow, 19).getDisplayValue();
var rec2 = notifysheet.getRange(activeRow, 20).getDisplayValue();
var email = rec1 + "," + rec2;
var subject = name + ': 201 Completion';
//Body of the email message, using HTML and the variables from above
var message =
'<br><div style="margin-left:10px;">Hi, </div>' +
'<br><div style="margin-left:10px;">Good day!</div>' +
'<br><div style="margin-left:10px;"><b>' + name + '</b> has completed the course. </div>' +
'<br><div style="margin-left:20px;"><h3 style="text-decoration: underline; color: #f36f21">Employee Details: </h3></div>' +
'<div style="margin-left:25px;">Name: <b>' +
name +
'</b></div>' +
'<div style="margin-left:25px;">Position: <b>' +
position +
'</b></div>' +
'<div style="margin-left:25px;">Team: <b>' +
team +
'</b></div>' +
'<div style="margin-left:25px;">Completion Date: <b>' +
date +
'</b></div>' +
'<br><br><div style="margin-left:10px;">Let me know if you have any questions. </div>' +
'<br><div style="margin-left:10px;">Thanks! </div>';
MailApp.sendEmail(email, subject, '', {
htmlBody: message,
name: 'Updates',
});
}
}
}
I read your code.
if you don't want your checked checkbox unchecked in spreadsheet.
so you have to remove `columnb2.setValue('false');` line of code.
this line is made checkbox unchecked.
solution of other problems : http://one7techlab.com

Time-driven trigger (daily) not triggering every day

I have the similar issue as described at How to make sure a daily time trigger runs?.
I have a specific script in one of the Google sheets with a daily trigger (time-driven, should trigger every morning, set up through interface, not programmatically). But the script doesn't execute every day. I can see this in the execution report, where there're just successful executions and no failed ones. I can also see if the script executed by checking a cell in the sheet which gets updated with the execution timestamp when the script runs. And I've set up an immediate notification for the failed executions in the trigger settings.
In my specific case, the script should ran every day from Nov 9 - Nov 13, but it ran just on Nov 9, Nov 10, Nov 12. And I didn't get any notification about the failed execution.
The script itself doesn't use any API, it's pretty basic: reading data in one sheet, doing some calculation and writing to another sheet (talking about the sheets in single Google Sheet file).
If I run the main function manually, it always works.
I'd be very glad to get some ideas what could be wrong. Thanks.
EDIT: Code sample (main function and prototype for Array.includes)
function main(){
var date = new Date();
//var date = new Date(2019, 9, 1); // year, month (zero-indexed!!!), day
//var date = new Date(date.getYear(), date.getMonth()-3); // testing
var currentDay = Utilities.formatDate(date, "CET", "d");
Logger.log('currentDate: ' + Utilities.formatDate(date, "CET", "YYYY-MM-dd HH:mm:ss.S") + ' | currentDay: ' + currentDay);
if (currentDay == 1) {
Logger.log('currentDay is 1st of the month');
date = new Date(date.getYear(), date.getMonth() - 1);
var newCurrentDay = Utilities.formatDate(date, "CET", "d");
}
var monthToCheck = Utilities.formatDate(date, "CET", "MMMM").toUpperCase();
var yearToCheck = Utilities.formatDate(date, "CET", "YYYY");
Logger.log('dateToCheck: ' + Utilities.formatDate(date, "CET", "YYYY-MM-dd HH:mm:ss.S") + ' | monthToCheck: ' + monthToCheck + ' | yearToCheck: ' + yearToCheck);
var firstProjectRow = 7; // first row with the project data
var firstProjectCol = 1; // first column with project data - should contain Tool IDs
var numOfProjectRows = 999; // num of project rows to check (counted from and including var firstProjectRow)
var numOfProjectCols = 21; // num of project columns to check (counted from and including var firstProjectCol the last one contains number of hours for the last service)
var firstProjectHoursCol = 7; // first column with data about project hours (usually PM hours)
// ************* DO NOT EDIT BELOW THIS LINE ************* //
//return;
var indexedFirstProjectHoursCol = firstProjectHoursCol - 1;
var ss = SpreadsheetApp.getActiveSpreadsheet();
//var sheet = ss.getSheets()[3];
var sheetName = monthToCheck + ' ' + yearToCheck;
var sheet = ss.getSheetByName(sheetName);
Logger.log('sheet: ' + sheetName);
var range = sheet.getRange(firstProjectRow, firstProjectCol, numOfProjectRows, numOfProjectCols); // getRange(row, column, numRows, numColumns)
var rangeValues = range.getValues();
//Logger.log('rangeValues: "' + rangeValues);
var toolData = new Array();
var toolIds = new Array();
var toolHours = new Array();
//return;
for (var row in rangeValues) {
Logger.log('row: "' + row);
var clientId = rangeValues[row][0];
var projectId = rangeValues[row][1];
var hoursSum = 0;
// we have Tool ID so it's OK to proceed
if (clientId != "" && projectId != "") {
var clientProjectId = clientId + "-" + projectId;
for (var col in rangeValues[row]) {
var cellValue = rangeValues[row][col];
//Logger.log('col: ' + col + ' value: ' + value);
// get hours sum
if (col >= indexedFirstProjectHoursCol)
hoursSum += typeof cellValue == 'number' ? cellValue : 0;
}
//Logger.log('hoursSum: [' + hoursSum + ']');
var record = {id: clientProjectId, hours: hoursSum};
Logger.log("Data: " + record.id + " : " + record.hours);
// don't yet have a record of clientId-projectId
if (!toolIds.includes(clientProjectId)) {
toolData.push(record);
}
else {
recordIdx = toolIds.indexOf(clientProjectId);
toolData[recordIdx].hours += hoursSum;
}
toolIds = [];
toolHours = [];
toolData.forEach(function(item) {
toolIds.push(item.id);
toolHours.push(item.hours);
});
}
//Logger.log(toolData);
//Logger.log('ROW DONE!');
}
Logger.log('ROWS DONE!');
Logger.log('toolData.length: ' + toolData.length);
toolData.forEach(function(item) {
Logger.log('toolData: ' + item.id + " : " + item.hours);
});
Logger.log('DONE!!!');
// fill the table in the sheet with assigned number of hours
fillTheSheet(sheetName, toolData);
}
Apps Script triggers have always been a bit finicky. But of late they have been far more unreliable than usual (there have been several reports of spurious triggers and other maladies).
In this case, you can avoid using them altogether by leveraging an external service such as cron-jobs.org.
You'll have to refactor your app script project and deploy it as a public Web App with a doPost(e) function. You'd then pass the Web App's url to the external service as a web-hook endpoint that is invoked daily.

Checking if specific column contain active cell

Just started my adventure with apps-script and im already stuck.
I'm trying to write script that triggers when any cell in my table is edited , check if that cell is in specific range ( entire column "O"), then gets cell row and sends mail to person bounded with that row.
As long as I got first and last part, I'm having trouble with checking if that range contains cell :
var cell = get.ActiveCell();
var range = ss.getRange("O:O");
However there are few similar columns with similar values, and i want to check this one only so far i got something like that
var ss = getActiveSpreadsheet();
var sheet = ss.getSheetByName("zamówienia");
var cell = get.ActiveCell();
var range =ss.getRange("O:O");
while (i != range.lenght){
if (cell != range[i]) {
i++;
}
else {
break;
return 1;
}
}
You should be using the onEdit() simple trigger, and then you can use the associated event object.
Example:
// This will show a pop up in your spreadsheet whenever you edit a cell in Column O of any sheet
function onEdit(e) {
var columnO = 15;
if (e.range.getColumn() === columnO) {
Browser.msgBox("Column O");
}
}
Got it like that if anybody's trying to sort out same problem. Added on edit simple trigger
function sprawdzenie(){
var ss = SpreadsheetApp.getActive();
var activeRow = ss.getActiveCell().getRow();
var activeCol = ss.getActiveCell().getColumn();
if (activeCol === 13){
var klient = SpreadsheetApp.getActiveSheet().getRange("c"+activeRow).getValue();
var data_wys = SpreadsheetApp.getActiveSheet().getRange("H"+activeRow).getValue();
var numer_oferty = SpreadsheetApp.getActiveSheet().getRange("E"+activeRow).getValue();
var kolor = SpreadsheetApp.getActiveSheet().getRange("B"+activeRow).getValue();
var prowadzacy = (SpreadsheetApp.getActiveSheet().getRange('AL'+activeRow).getValue() );
var zejscie = SpreadsheetApp.getActiveSheet().getRange("M"+activeRow).getValue();
var temat = ('Zejście z produkcji ' + numer_oferty + ' wysłanej dnia ' + data_wys);
var wiadomosc = (' Oferta o numerze :' + numer_oferty + ' ' + klient + ' w kolorze : ' + kolor + ' zeszła z dniem : ' + zejscie);
MailApp.sendEmail(prowadzacy, temat, wiadomosc);}

onEdit timestamp for specific sheet

I am looking for help with a script that posts that a specific sheet has been edited rather than when any sheet in the document is modified.
Here is what I currently have:
function onEdit() {
var d = new Date();
var h = d.getHours();
var min = d.getMinutes();
var sec = d.getSeconds();
var h_str = h;
var min_str = min;
var sec_str = sec;
// format time nicely
if (h < 10)
h_str = '0' + h;
if (min < 10)
min_str = '0' + min;
if (sec < 10)
sec_str = '0' + sec;
// create the formatted time string
var time_str = h_str + ':' + min_str + ':' + sec_str;
// create the message
var s = 'Roster last modified on: ' + d.toDateString() + ' # ' + time_str;
// change the range
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Infernal Dawn').getRange("A1").setValue(s);}
This works perfectly fine to only update the sheet "Infernal Dawn" with the modification date, yet it also updates when ANY sheet is modified.
I found that there were 2 different ways of doing this (one using the gid). The only problem is that my skills in coding are extremely limited and I couldn't figure out how to integrate it into the above code. Any help would be appreciated!
The function onEdit has an optional argument that remembers which cell\range\sheet was edited. The structure of this argument is described here.
function onEdit(e)
{ var d=new Date();
var s=d.toLocaleString();
if(e.source.getActiveSheet().getName()=="TheSheetThatWeWishToTrace")
{ SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Infernal Dawn').getRange("A1").setValue(s);}
}