Google Sheet Script not fully executing - google-apps-script

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

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.

Need Script for Google Docs to Send Auto Email

I'm looking for a script that I can add to a Google sheet that will auto generate an email and include some of the fields in the spread sheet.
I had created a Google Form and I have that data going to the Google spreadsheet, the idea is when the user submits the form it sends that data to the spreadsheet and the spreadsheet sends an automated email.
I found this script and edited it some but it fails on the 4th line (var theEvent = e.values[1]):
function AutoConfirmation(e){
var theirFirst = "Bill";
var theirEmail = johndoe#example.com;
var theEvent = e.values[1];
var subject = "Form Submitted";
var message = "Thank you, " + theirFirst + " for the expressed interest in our " + theEvent;
MailApp.sendEmail (theirEmail, subject, message);
}
Shouldn't line 4 pull the data from column 1 in my google sheet? Is this old an script and it doesn't work now?
In my google sheet I have Site instead of event as a column and another that has Complete as a header.
Let me know what I have missed here as it seems that this should be simple.
I tried to run this and this is the result: screenshot of the error I get
I get the same type of error when running the code above so I thought I would run a logger to see if I get anything with that and the result is in the screen shot. Click the link to see it.
It looks that the script that you found is function to be put in a Apps Script project bounded to a Google spreadsheet and called by an installable trigger.
Shouldn't line 4 pull the data from column 1 in my google sheet?
No. e.values returns an Array which use a zero based index. This means that index for Column A, the first column, is 0.
Issue:
The error you are getting:
TypeError: Cannot read property 'values' of undefined
Means that the event object (e) is undefined, which means that you are trying to run this function manually. Functions that are attached to a trigger are supposed run when the corresponding trigger event happens: in this case, when a user submits the Form. You don't have to run it manually.
Solution:
Step 1: Install the trigger: If you haven't done so yet, install the trigger, either manually, following these steps, or programmatically, by copy the following function to your bound script and running it once:
function createOnFormSubmitTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("AutoConfirmation")
.forSpreadsheet(ss)
.onFormSubmit()
.create();
}
Step 2: Submit the form!: Once the trigger is installed, when a user submits the Form that is attached to your Spreadsheet (that is, assuming that you have attached the Form to the Spreadsheet), AutoConfirmation runs automatically, and the event object, containing these properties, is passed as an argument. If you run it manually, e is undefined (no event object is passed as parameter), and you get the error.
Note:
e.values[1] will retrieve the same value that is written to column B when the form is submitted, since JavaScript arrays are zero-indexed. You might want to use e.namedValues['yourProperty'] instead, to make sure your are retrieving the desired information.
Reference:
SpreadsheetTriggerBuilder.onFormSubmit()
Event Objects: Form submit

Apps Script: how do you copy values from specific columns to a different spreadsheet via a time trigger, button press or sheet update?

I need to copy the values of multiple ranges of data from my main spreadsheet into another spreadsheet and then copy a different range of data back to the main spreadsheet.
Here are my example spreadsheets:
The main spreadsheet (two sheets: 1 - A sheet of pasted values alongside columns of user comments. 2 - A sheet with a button that runs the Apps Script)
The live data spreadsheet (pulls and formats the required data from other sheets).
Previously, I’ve used .copyTo() to copy the values of data and paste them elsewhere on the same spreadsheet. However, this method can’t be used to copy data to a different spreadsheet. Copying data from multiple ranges is also causing me issues. Here is my code:
function RefreshSheetData() {
// 1a. Run the script when a button is pressed (Main Spreadsheet - ‘Update report button!A3’)
// 1b. Run the script at a certain time (every Monday at 10 AM)
// 1c. Run the script when data in a sheet is replaced with new data via a formula – NOT POSSIBLE.
// 2. Copy email address and user comments (Main Spreadsheet - Editable report - J3:J & AM3:AR)
// 3. Clear the “Updated user comments” sheet below the header row (Live data Spreadsheet - Updated user comments - A2:G)
// 4. Paste the values (Live data Spreadsheet - Updated user comments - A2:G)
// 5. Clear the “Editable report” below the header rows (Main Spreadsheet - Editable report – B3:AR)
// 6. Copy the Live sheet (which should now include the most recent user comments via array vlookup) (Live data Spreadsheet - live data – A3:AQ)
// 7. Paste the values (Main Spreadsheet - Editable report - B3:AR)
// 8. Add the (United Kingdom) time and date (Main Spreadsheet - Update report button - A10)
// 9. Add the time and date (Live data Spreadsheet - Updated user comments - J1)
ScriptApp.newTrigger('RefreshSheetData')
.timeBased()
.onWeekDay(ScriptApp.WeekDay.MONDAY)
.atHour(10)
.create();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var startSheet = ss.getSheetByName('Editable report');
var sourceRange = startSheet.getRangeList(['J3:J', 'AM3:AR']);
var sourceValues = sourceRange.getValues();
var target = SpreadsheetApp.openById('1OHQHefYvE4vZZPr8jgziy_L3-UBf1WSoKzMWQ8LUz6w');
var targetSheet = target.getSheetByName('Updated user comments');
var clearTargetRange = targetSheet.getRange('A2:G').clearContent();
var targetRange = targetSheet.getRange('A2').setValues(sourceValues);
var liveTargetSheet = target.getSheetByName('Live data');
var liveSourceRange = liveTargetSheet.getRange('A3:AQ').getValues();
var clearMainRange = startSheet.getRange('B3:AR').clearContent();
var startRange = startSheet.getRange('B3').setValues(liveSourceRange);
SpreadsheetApp.getActive().getRange('A10').setValue(new Date());
targetSheet.getRange('J1').setValue(new Date())
}
Any tips would be appreciated. Thank you.
Part of my question was how to trigger a script when a formula output changes. That’s not possible. Neither .onEdit or .onChange triggers work as they only respond to user actions. They won't run when the value of an IMPORTRANGE or alternative formula changes.
Here some suggestions referring to each of the steps mentioned in your Apps Script file
1b. To run the script at a certain time: please use the installable trigger "Time driven"
1c. To run the script when data in the sheet is updated: please use the onEdit trigger
1d. You can combine all triggers by simply adding as many, as required.
To copy and paste data, you just need the methods getValues() and setValues(), which you were using already, the important thing is that you chose the "to copy" range correctly.
You can clear a range with clear()
See 3.
You can copy a sheet with copyTo(), however keep in mind that if using this method, your data in the copied sheet will automatically be updated if there is a change in the original sheet. If you want the values to remain static, you have to copy and paste them with copyValues() and setValues().
See 2. and 5.
See here how to get and format the date in Apps Script
Assign the date to a variable and use setValue()
I encourage you to try and build the script based on those steps
yourself, the Apps Script documentation provides you good reference
and guidance, how to do so. If you encounter specific problems during
one of the steps which you cannot solve with the documentation, feel
free to ask!

Trigger a script when a formula changes a cell value

I'm using a Google script then sends out an email when a certain column in a Google sheet is changed. The information in the cell is either inputted manually, or completes using a formula based on information in other cells.
The script works fine when information is manually entered, but not when the formula runs. I've read up on it and realise that a formula calculation doesn't count as an edit, so how do I get the script to run?
It's currently set up to trigger from the spreadsheet when there's an edit.
Below is the part of my script that covers the column/cell in question.
function sendEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var row = sheet.getActiveRange().getRow();
var cellvalue = ss.getActiveCell().getValue().toString();
if(sheet.getActiveRange().getColumn() == 12)
There's a lot more included in the script so I haven't copied everything onto here. Many thanks in advance.
There is no trigger that can run when a formula changes.
Try figure out, what conditions is your formula depends on:
if it is another cell, entered manually, then use those cell to trigger it's changes with onEdit
if the formula imports data from external source, use random or time functions, you'd better use onTime trigger.
if the formula uses importrange then go to the range you import and see the original range, return to step 1 → 2...

Spreadsheet Email Trigger

I have Written Script on Google Spreadsheet to send Email when spreadsheet is modified or any Data is added. Email Trigger is working but whenever any data is entered in next Row it send Email to previous email address also.
Please suggest solution
The below is written script :
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 1; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1 , numRows,3) // Fetch the range of cells A2:B3
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var emailAddress = row[2]; // First column
var message = row[0] + "requested" + row [1]; // Second column
var subject = "Sending emails from a Spreadsheet";
MailApp.sendEmail(emailAddress, subject, message);
}
}
Your question is unclear... nowhere in the script I see something that reads which cell is actually modified... your target range is hardcoded on row 2 so the only row that can be processed is row 2 (and the mail can only be sent once)...
So can you :
explain how it should work
explain how it works now , especially what do you mean by 'previous email'
remove typos in your code (row[2] is not First column)
explain how you trigger this function : the name onEdit(e) suggest an onEdit trigger but simple triggers cannot send mail so I suppose you have set some other trigger.
explain why (e) in your function parameter and not using it ?
EDIT : thanks for the complement of information.
The script you suggest is not sufficient to achieve what you want. The idea here is to check if something in the sheet has been modified either by adding (or inserting) a row of data or (if I understood well) by editing any row in the sheet with a new value.
This is not really as simple as it looks at the first glance ;-)
What I would do it to take a 'snapshot' of the sheet and -based on a timer or onEdit - compare that snapshot to the sheet's current state.
There is more than one way to get that result, you could have a second sheet in your spreadsheet that no one could modify and that is a copy of the main sheet that you update after each modification/mail send. So before updating the script should look for any difference between the sheets and send a report to the corresponding email when a difference is found.
Another way to do that is to store the sheet data converted to a string in the script properties, the principle is the same but it's more 'invisible' for normal users accessing the spreadsheet.
You could also use scriptDb or your userproperties but the script properties is probably better suited (simpler) for this use case.
Tell us what you think/prefer and I (or someone else) could probably give you some code to start with.
It appears that you're using a shared spreadsheet to collect the add-user-requests, and trusting the requesters to fill in the information. In the detail document you shared, it further appears that requests are ADDED, but not EDITED. (That's an important simplifying distinction.)
I suggest that what you really need is to use a form for receiving that input. Using a form will create a "data table" within your spreadsheet, a set of columns that you must not mess with. (You can edit the contents, add and delete rows, but must not add or remove columns.) However, you CAN add columns to the spreadsheet outside of this table, which gives you a handy place to store state information about the status of individual requests.
Further, you can trigger your processing to run on form submit, rather than a simple "onEdit" - this gets away from the problem that ScampMichael pointed out. Alternatively, you can use an installable edit trigger, as described in this answer.
Try this sheet, and this form. Save yourself a copy, go into the script and remove the comments that are stopping emails from being sent, and try it out. There's a menu item in the spreadsheet that can kick off processing; just clear the "Request State" column to re-run it. You can open the form (and find its URL), and add more entries to experiment.
It's the core of a similar system that I've written, and contains a discreet state machine for processing the requests. My system has large amounts of very complex data in multiple spreadsheets, so it often gets pre-empted, then needs to run again. (I use a timed trigger for that.) That's why requests are handled through states. If you find that too complex, pull out only the parts you need.