Creating a timestamp on a time trigger? - google-apps-script

-Need to create a timestamp every day at 6, checking to see if a specific column has been updated. I have the time trigger running, I get the emails that it tried to run but 'script function not found: myFunction'.
I know I need to make 'myFunction' but should I just be using a onEdit? I'm not sure how to get it to work so every day at 1 pm, it checks a specific column for an edit, then gives a timestamp in another column if it was edited.
I tried a few times to figure out how to get the active range sorted, but I don't know if the trigger is just running 'myFunction' at the specified time, and if I just need to write code then point the trigger at it.
function createTimeDrivenTriggers() {
ScriptApp.newTrigger('myFunction')
.timeBased()
.everyDays(1)
.atHour(13)
.create();
var timeZone = Session.getScriptTimeZone();
var timestamp_format = "mm/dd/yyyy";
var updateColName = "Updated";
var timeStampColName = "Timestamp";
var ss = SpreadsheetApp.getActiveSpreadsheet();

Do not use onEdit. That means "run every time someone edits this sheet."
Yes, you must write myFunction first. Run it and debug it manually before you attach a trigger to it.
Do not attach the trigger with ScriptApp. Click on the trigger button in the script editor, which will take you to the script.google.com dashboard where you can use a trigger setup wizard to set the trigger correctly to run 'myFunction' between 1-2pm.

Related

Trigger bug when copying rows

I have a function that copies rows from one sheet to another, which works when I run it manually:
function updateDataRange() {
var formSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses 1");
var lastFormRow = formSheet.getLastRow();
var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DataRange");
dataSheet.clear();
for(var rowCounter = 1; rowCounter <= lastFormRow; rowCounter++) {
var sourceRange = formSheet.getRange('B'+rowCounter+':H'+rowCounter);
var insertRow = dataSheet.getLastRow() + 1;
var targetRange = dataSheet.getRange('A'+insertRow);
sourceRange.copyTo(targetRange);
}
}
However, when I run this via a trigger (e.g. function onEdit(e) { updateDateRange(); } ), there are gaps in the rows and some of the values will be left out. In this case, I know there is a "fix" by using rowCounter instead of insertRow to write the files instead of using getLastRow(), but one can easily see how this is a problem in another scenario.
So I guess my question is simple: Why isn't this working correctly when using a trigger?
Edit: To clarify, I have a 3rd sheet with some conditions/cells (i.e. conditions that influence which rows are to be copied) and changing them (like changing a different date) trigger the function.
Explanation:
You are using an onEdit trigger to capture sheet changes. But onEdit triggers work only when the user changes the value of a cell. Referencing the official documentation:
The onEdit(e) trigger runs automatically when a user changes the value
of any cell in a spreadsheet.
In your case, I think you are trying to execute this code when the Form Responses sheet is filled in with data by the form.
There are two kind of trigger functions that work with form submissions and they are both installable.
One is a google sheet event based trigger and the other one a form event based trigger.
Your goal is to execute some code from the google sheets side, so it makes sense to use the first one.
Modifications:
Change the name of the function from onEdit to a different name of your choice e.g. myFormSubmitTrigger.
Since the trigger is installable you need to "install" a onFormSubmit trigger for the myFormSubmitTrigger function. Here you can find some simple instructions on how to do that.
If your question is why doesn't your function work when the form makes changes to sheet Form Responses 1 then Marios has answered you question accept it and move on. If your trying to run your function when a user is making edits to sheet Form Responses 1 using a simple trigger then a possible explanation for not getting all of the rows completely copied is that simple trigger must complete in 30 seconds. If you continue to accept more data in Form 1 Responses then soon or later you will have problems but with this function it will be a lot later because it will run much faster than your code:
function updateDataRange() {
const sss=SpreadsheetApp.openById('ssid');
const ssh=e.source.getSheetByName('Form Responses 1');
const sr=2;
const svs=ssh.getRange(sr,2,sh.getLastRow()-ssr+1,7).getValues();
const dsh=e.source.getSheetByName('DataRange');
dsh.clear();
dsh.getRange(1,1,svs.length,svs[0].length).setValues(svs);
}
However, I would recommend that you never edit a form responses sheet. I would consider using the onFormSubmit trigger to capture all of the data to a second sheet that is available to edit. And it will have additional data automatically appended to it via dsh.appendRow(e.values). And so now you would no longer require an onEdit trigger because your data sheet is kept upto data with an onFormSubmit trigger and you may feel free to edit the datasheet any time you wish.
If neither of these questions suffices then I would recommend that you be more clear about what you are asking.

retrieving google sheets cell for calendar returns "last updated"

I currently have a google sheets script that's automated to create a google calendar event daily at a specific time from a google sheets cell. When I execute it manually, it works. But when I allow it to automatically execute at that specific time it simply creates a calendar event with the title "last updated." Any idea why? I've included the code below:
function sheets_to_calendar(){
var mycal = "xxx#gmail.com";
var event = CalendarApp.getCalendarById(mycal);
var Title = SpreadsheetApp.getActiveSheet().getRange('J1').getValue();
var date = new Date();
var description = SpreadsheetApp.getActiveSheet().getRange('F2').getValue();
event.createAllDayEvent(Title, date, {description: description});
}
You should check how many triggers are in your project
In order to avoid your code running twice at the specific time you mentioned, keep in mind Google Calendar events are separated in 30 minutes time range, in other words, e.g. if there are 2 triggers running at 08:00 AM and 08:29 AM they are still the same Calendar event, that's why you get your event updated.
If the error persists, try to create your trigger programatically
As I can see in your question, you are managing time-driven triggers, for that reason as a workaround you can create a temporary function in your project and create your trigger using code:
/**
* Creates two time-driven triggers.
*/
function createTimeDrivenTriggers() {
// Trigger every 6 hours.
ScriptApp.newTrigger('myFunction')
.timeBased()
.everyHours(6)
.create();
// Trigger every Monday at 09:00.
ScriptApp.newTrigger('myFunction')
.timeBased()
.onWeekDay(ScriptApp.WeekDay.MONDAY)
.atHour(9)
.create();
Which is recommended because using new Date() is using the time on server.
References
Calendar.createAllDayEvent
Installable Triggers

Google Sheet Script not fully executing

I'm using a Google Form to trigger this script.
When I run the script with the Play button it works perfect.
When I let the onsubmit trigger run it, the check box populates fine but the setValue date does not.
I've also tried using setFormula but I get the same result.
function AddCheckBox_toSchoolLunchForm(F) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses 1")
var criteria = SpreadsheetApp.DataValidationCriteria.CHECKBOX;
var rule = SpreadsheetApp.newDataValidation().requireCheckbox().build();
var range = sheet.getRange(sheet.getLastRow(), 8);
range.clearContent();
range.setDataValidation(rule);
var FormulaCell = sheet.getRange(sheet.getLastRow(), 10);
FormulaCell.setFormula("=DATEVALUE(A" + (sheet.getLastRow()) + ")");
}
The end goal is to have column J populate with the shot formatted date from column A each time the form is submitted.
I need this format to run a countIfs on another sheet.
Another option would be to somehow embed a format tag into this CountIfs command so that they match.
=COUNTIFS('Form Responses 1'!J:J,A2,'Form Responses 1'!D:D,B2)
UPDATED ANSWER
If you have problems running a function on trigger while it works as intended without a trigger, check the following:
For heavy files / form data they can be a delay in populating the sheet with new form data.
To avoid conflicts, give the spreadsheet some time to populate the new row before retrieving sheet.getLastRow() or accessing data in the sheet.
You can dot is easily e.g. with Utilities.sleep().
Check that your trigger has been installed correctly. For this check that
the type of trigger is correct
the trigger is bound to the correct function
avoid conflicts by creating a new trigger when renaming the funciton.
Check that the problem is not due to trigger restrictions
This is a common error source when using simple triggers.
Check that account under whose authorization the trigger is running has permissions to edit the sheet /range. This is important to check when the trigger owner is a diferent person that the person who runs the script manualy.
Note that for setFormula() it is not necessary to incorporate the = into the formula
Note that DATEVALUE() will only return the expected result when the cell is formatted correctly as a date

Run a trigger X amount of time after an edit

I would like to get a trigger to run a specified amount of time after an edit occurs.
I'm thinking that I could someone combine an edit trigger and a time based trigger for this functionality, but am not clear how.
To provide some additional detail.
I have a Google Sheet where I track my insulin usage. I am supposed to check my blood sugar 2 hours after I administer my insulin.
When I administer the insulin I make an entry into Google Sheets, time/amount/etc... When I make this entry I would like to create a trigger that will run in 2 hours to send me an email notification as a reminder to check my blood sugar again and make a new entry.
This is how I use time triggers in Google App Script.
Function to create the time trigger.
function createTriggger(name,action,time){
// Time is in minutes
var trigger = ScriptApp.newTrigger(action)
.timeBased()
.after(time*60*1000)
.create();
var triggerID = trigger.getUniqueId();
// Store trigger id to delete the trigger once it has executed
PropertiesService.getScriptProperties().setProperty(name, triggerID);
};
This name is the name of the property to store the trigger id, so you can delete the trigger after it executes. action is the name of the function you want the trigger to execute, and time is in minutes.
On the last line of your function that you want the trigger to execute, use this line to grab the trigger id and delete it from your trigger list. Put the name of your trigger id property in name.
var triggerID = PropertiesService.getScriptProperties().getProperty(name)
deleteThisOne(triggerID)
Here is the delete funciton:
function deleteThisOne(id){
var triggers = ScriptApp.getProjectTriggers();
for(var i=0;i<triggers.length;i++){
if(triggers[i].getUniqueId() == id){
ScriptApp.deleteTrigger(triggers[i]);
break;
};
};
};
Look at google scripts Installable Triggers for Limitations
When your edit trigger fires, you could use a ClockTrigger - see the ClockTriggerBuilder documentation and example, which allows you to either set a time relative to the current execution time, or at an absolute time.
You can use a work around like this:
Set '0' value in some corner cell in spreadsheet which you won't modify ever. Hide that column.
Set onEdit trigger on spreadsheet and write its function, which sets the value '0'.
Set another trigger which is triggered every 10 minutes to increment that cell value by 10 every time. Also add this to that function:
if(cellValue%120 == 0)
{
setReminder(); //function to send you reminder
cellValue = 0;
}

How to create a time based trigger for a google spread sheet created with apps script

I wonder if there is a way to create a time based trigger fir a google spread sheet created with google apps script.I googled a lot and no luck.what i am exactly looking for is,i created a google spread sheet and took the id of that spread sheet like this
var spreadSheet = SpreadsheetApp.create('Google Contacts');
var id = spreadSheet.getId();
PropertiesService.getScriptProperties().setProperty('ssId', id);
and then i was trying to create a trigger for this spread sheet like this
ScriptApp.newTrigger("myTrigger").timeBased().everyMinutes(1).create();
and myTrigger is this
function myTrigger(e) {
var range = e.range;
range.setNote('Last modified: ' + new Date());
}
I want to run this trigger ,ie,this time based trigger on my spread sheet created with the previous method.And now i don't find a way for this.
What i am looking for is, i want to run this time based trigger on the spread sheet with this id
var id = PropertiesService.getScriptProperties().getProperty('ssId');
I was able to create this trigger for this spread sheet with the code ScriptApp.newTrigger('myTrigger').forSpreadsheet(id).onEdit().create(); but this is not triggering on a time based ,rather than it is triigering on editof the above spread sheet.
Thanks.
The issue here is your trigger function myTrigger is coded to expect an onEdit event rather than an time based trigger event, as a result the script simply crashes when your time-based trigger calls it.
You can probably see details of this failure in the Execution Transcript of your Script Editor.
The reason is the reference to e.range, with an OnEdit trigger e.range is the edited range, but on a time-based trigger e.range is undefined. This is because the time-based trigger has nothing to do with any given range of cells.
Since your goal seems to be to set a note saying when a given range was last modified, I don't think you can easily achieve your final goal with a time-based trigger, why not simply use the onEdit trigger?
If you want to interact with the spreadsheet from your time based trigger, you will need to open the spreadsheet and get the range, then take your actions.
function myTrigger(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getRange("A1:B1");
range.setNote('...')
You can see the different properties of event vs time-driven triggers listed in the tables here: https://developers.google.com/apps-script/guides/triggers/events#google_sheets_events