automatically create google contact from my google form - google-apps-script

I have a google form that my clients fill out. How do I have the form create a google contact automatically each time someone new fills out the survey? I dont want to have to copy paste each time just to create a new contact in my gmail
I'm trying to use this script but getting an error when I try to run it with some test data
function onFormSubmit(e) {
var timestamp = e.values[0];
var firstName= e.values[1];
var lastName= e.values[2];
var email= e.values[3];
var phone= e.values[4];
ContactsApp.createContact( timestamp , firstName , lastName , email , phone );
}
TypeError: Cannot read property "values" from undefined. (line 2

You will get that error message when attempting to run the function manually, as there is no event being passed to the function.
Disregard the remainder of the post (see Henrique's comment).
According to the documentation:
An event is passed to every event handler as the argument (e) . You
can add attributes to the (e) argument that further define how the
trigger works or that capture information about how the script was
triggered.
If you use the attributes, you must still set the trigger from the
Resources menu, as described in the sections above.
https://developers.google.com/apps-script/guide_events#TriggerAttributes
I can't explain why this is the case, but it seems you need to use the
simple event handler (ie naming the function onFormSubmit), as well as
applying an installable event handler to that same function. Then,
for me at least, it works as expected.
HTH, Adam

There's no "phone" argument in createContact function. Before attempting to create it from a more difficult to debug trigger, have you tried writing a simple function to create a simple contact just to check that you got it right?
Also, I remember an old error with on form submit parameters, that may be back. Anyway, it doesn't hurt to add a toString in all your parameters. e.g.
var email = e.values[3].toString(); //just to be sure

Related

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

Refresh data retrieved by a custom function in Google Sheet

I've written a custom Google Apps Script that will receive an id and fetch information from a web service (a price).
I use this script in a spreadsheet, and it works just fine. My problem is that these prices change, and my spreadsheet doesn't get updated.
How can I force it to re-run the script and update the cells (without manually going over each cell)?
Ok, it seems like my problem was that google behaves in a weird way - it doesn't re-run the script as long as the script parameters are similar, it uses cached results from the previous runs. Hence it doesn't re-connect to the API and doesn't re-fetch the price, it simply returns the previous script result that was cached.
See more info here(Add a star to these issues, if you're affected):
https://issuetracker.google.com/issues/36753882
https://issuetracker.google.com/issues/36763858
and Henrique G. Abreu's answer
My solution was to add another parameter to my script, which I don't even use. Now, when you call the function with a parameter that is different than previous calls, it will have to rerun the script because the result for these parameters will not be in the cache.
So whenever I call the function, for the extra parameter I pass "$A$1".
I also created a menu item called refresh, and when I run it, it puts the current date and time in A1, hence all the calls to the script with $A$1 as second parameter will have to recalculate. Here's some code from my script:
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Refresh",
functionName : "refreshLastUpdate"
}];
sheet.addMenu("Refresh", entries);
};
function refreshLastUpdate() {
SpreadsheetApp.getActiveSpreadsheet().getRange('A1').setValue(new Date().toTimeString());
}
function getPrice(itemId, datetime) {
var headers =
{
"method" : "get",
"contentType" : "application/json",
headers : {'Cache-Control' : 'max-age=0'}
};
var jsonResponse = UrlFetchApp.fetch("http://someURL?item_id=" + itemId, headers);
var jsonObj = eval( '(' + jsonResponse + ')' );
return jsonObj.Price;
SpreadsheetApp.flush();
}
And when I want to put the price of item with ID 5 in a cell, I use the following formula:
=getPrice(5, $A$1)
When I want to refresh the prices, I simply click the "Refresh" -> "Refresh" menu item.
Remember that you need to reload the spreadsheet after you change the onOpen() script.
You're missing the fastidious caching bug feature. It works this way:
Google considers that all your custom functions depend only on their parameters values directly to return their result (you can optionally depend on other static data).
Given this prerequisite they can evaluate your functions only when a parameter changes. e.g.
Let's suppose we have the text "10" on cell B1, then on some other cell we type =myFunction(B1)
myFunction will be evaluated and its result retrieved. Then if you change cell B1 value to "35", custom will be re-evaluated as expected and the new result retrieved normally.
Now, if you change cell B1 again to the original "10", there's no re-evaluation, the original result is retrieved immediately from cache.
So, when you use the sheet name as a parameter to fetch it dynamically and return the result, you're breaking the caching rule.
Unfortunately, you can't have custom functions without this amazing feature. So you'll have to either change it to receive the values directly, instead of the sheet name, or do not use a custom function. For example, you could have a parameter on your script telling where the summaries should go and have an onEdit update them whenever a total changes.
What I did was similar to tbkn23. This method doesn't require any user action except making a change.
The function I want to re-evaluate has an extra unused parameter, $A$1. So the function call is
=myFunction(firstParam, $A$1)
But in the code the function signature is
function myFunction(firstParam)
Instead of having a Refresh function I've used the onEdit(e) function like this
function onEdit(e)
{
SpreadsheetApp.getActiveSheet().getRange('A1').setValue(Math.random());
}
This function is triggered whenever any cell in the spreadsheet is edited. So now you edit a cell, a random number is placed in A1, this refreshes the parameter list as tbkn23 suggested, causing the custom function to be re-evaluated.
There are settings where you can make NOW() update automatically:
If your custom function is inside a specific column, simply order your spreadsheet by that column.
The ordering action forces a refresh of the data, which invokes your custom function for all rows of that column at once.
Script Logic:
Custom Functions don't update unless it's arguments changes.
Create a onChange trigger to change all arguments of all custom functions in the spreadsheet using TextFinder
The idea to add a extra dummy parameter by #tbkn23 and use of the triggers by #Lexi Brush is implemented here with a random number as argument. This answer mainly differs due to usage of class TextFinder(a relatively new addition to Apps script), which is better because
No extra cell is required.
No menu is needed > No additional clicks needed. If you need a custom refresher, a checkbox is a better implementation
You can also change the formula itself instead of changing the parameters
The change/trigger can be configured to filter out only certain changes. For eg, the following sample script trigger filters out all changes except INSERT_GRID/REMOVE_GRID(Grid=Sheet). This is appropriate for the custom function that provides sheetnames. A edit anywhere isn't going to change the list of sheets/sheetnames, but inserting or removing sheet does.
Sample custom function(to refresh):
/**
* #customfunction
* #OnlyCurrentDoc
* #returns Current list of sheet names
*/
const sheetNames = () =>
SpreadsheetApp.getActive()
.getSheets()
.map((sheet) => sheet.getName());
Refresher function:
/**
* #description Automatically refreshes specified custom functions
* #author TheMaster https://stackoverflow.com/users/8404453
* #version 2.0.0
* #changelog
* Updated to support all custom functions and arguments
* Avoid eternal loops
*/
/**
* #listens to changes in a Google sheet
* #see https://developers.google.com/apps-script/guides/triggers/installable#managing_triggers_manually
*/
function onChange(e) {
/* Name of the custom function that is to be refreshed */
const customfunctionName = 'SHEETNAMES',
regexPattern = `=${customfunctionName}${String.raw`\(([^)]*?)?(?:,\s*?"RANDOM_ID_\d+")?\)`}`,
replacementRegex = `=${customfunctionName}${String.raw`($1,"RANDOM_ID_${
Math.floor(Math.random() * 500) + 1
}")`}`;
/* Avoid eternal loop
* Increase timeout if it still loops
*/
const cache = CacheService.getScriptCache(),
key = 'onChangeLastRun',
timeout = 5 * 1000 /*5s*/,
timediff = new Date() - new Date(JSON.parse(cache.get(key)));
if (timediff <= timeout /*5s*/) return;
cache.put(key, JSON.stringify(new Date()));
/* Following types of change are available:
* EDIT
* INSERT_ROW
* INSERT_COLUMN
* REMOVE_ROW
* REMOVE_COLUMN
* INSERT_GRID
* REMOVE_GRID
* FORMAT
* OTHER - This usually refers to changes made by the script itself or sheets api
*/
if (!/GRID|OTHER/.test(e.changeType)) return; //Listen only to grid/OTHER change
SpreadsheetApp.getActive()
.createTextFinder(regexPattern)
.matchFormulaText(true)
.matchCase(false)
.useRegularExpression(true)
.replaceAllWith(replacementRegex);
}
To Read:
Installable triggers
TextFinder
As noted earlier:
Custom Functions don't update unless it's arguments changes.
The possible solution is to create a checkbox in a single cell and use this cell as an argument for the custom function:
Create a checkbox: select free cell e.g. [A1], go to [Insert] > [Checkbox]
Make this cell an argument: =myFunction(A1)
Click checkbox to refresh the formula
Use a google finance function as a parameter. Like =GOOGLEFINANCE("CURRENCY:CADARS")
Those function force reload every x minutes
Since google app script is an extension of JS, functions should be able to handle more args than defined in function signature or fewer. So if you have some function like
function ADD(a, b) {
return CONSTANTS!$A$1 + a + b
}
then you'd call this func like
=ADD(A1, B1, $A$2)
where $A$2 is some checkbox (insert -> checkbox) that you can click to "refresh" after you needed to change the value from the sheet & cell CONSTANTS$A$1
I use a dummy variable in a function, this variable refers to a cell in the spreadsheet. Then I have a Myfunction() in script that writes a Math.Random number in that cell.
MyFunction is under a trigger service (Edit/Current Project Triggers) and you can choose different event-triggers, for example On-Open or time driven, there you can choose for example a time period, from 1 minute to a month.
Working off of Lexi's script as-is, it didn't seem to work anymore with the current Sheets, but if I add the dummy variable into my function as a parameter (no need to actually use it inside the function), it will indeed force google sheets to refresh the page again.
So, declaration like: function myFunction(firstParam,dummy) and then calling it would be as has been suggested. That worked for me.
Also, if it is a nuisance for a random variable to appear on all of your sheets that you edit, an easy remedy to limit to one sheet is as follows:
function onEdit(e)
{
e.source.getSheetByName('THESHEETNAME').getRange('J1').setValue(Math.random());
}
another solution to the caching problem.
have a dummy variable in your method.
pass
Filter(<the cell or cell range>,1=1)
as the value to that parameter.
e.g.
=getValueScript("B1","B4:Z10", filter(B4:Z10,1=1))
the output of filter is not used. however it indicates to the spreadsheet that this formula is sensitive to B4:Z10 range.
I had a similar issue creating a dashboard for work. Chamil's solution above (namely using Sheet's Filter function passed as the value to a dummy variable in your function) works just fine, despite the more recent comment from Arsen. In my case, I was using a function to monitor a range and could not use the filter on the same range since it created a circular reference. So I just had a cell (in my case E45 in the code below) in which I changed the number anytime I wanted my function to update:
=myFunction("E3:E43","D44",filter(E45,1=1))
As Chamil indicated, the filter is not used in the script:
function myFunction(range, colorRef, dummy) {
variable 'dummy' not used in code here
}
Today I solved this by
adding another parameter to my function:
function MY_FUNC(a, b, additional_param) { /* ... */ }
adding a value to this parameter as well, referencing a cell:
=MY_FUNC("a", "b", A1)
and putting a checkbox in that referenced cell (A1).
Now, it takes only one click (on the checkbox) to force recalculating my function.
What you could do is to set up another cell somewhere in the spreadsheet that will be updated every time a new sheet is added. Make sure it doesn't update for every change but only when you want to do the calculation (in your case when you add a sheet). You then pass the reference to this cell to your custom function. As mentioned the custom function can ignore this parameter.
Given that feature explained by Henrique Abreu, you may try the out-of-box spreadsheet function QUERY , that SQL liked query is what I use often in work
on raw data, and get data as summary to a different tab, result data is updated in real time following change in raw data.
My suggestion is based on the fact that your script has not advanced work such as URL fetch, just data work, as without actual data read, I cannot give a precise solution with QUERY.
Regarding the cache feature mentioned by Henrique Abreu (I don't have enough reputation to comment directly under his answer), I did testing and found that:
looks there is no cache working, testing function's script shown below:
function adder(base) {
Utilities.sleep(5000);
return base + 10;
}
applying that custom function adder() in sheet by calling a cell, and then changed that cell value forth and back, each time I see the loading message and total time more than 5 seconds.
It might be related to the update mentioned in this GAS issue:
This issue has now been fixed. Custom functions in New Sheets are now context aware and do not cache values as aggressively.
the issue mentioned in this topic remains, my testing suggests that, Google sheet recalculate custom function each time ONLY WHEN
value DIRECTLY called by function is changed.
function getCellValue(sheetName,row,col)
{
var ss= SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName(sheetName);
return sh.getRange(row, col).getValue();
}
A change of any value in yellow cells will lead to recalculation of custom function; the real data source value change is ignored by function.
function containing cell's location is changed in sheet. ex. insert/remove a row/column above or left side.
I did not want to have a dummy parameter. YMMV on this.
1 A cell that is a 'List of Items', one is "Refresh"
2 Script with 'onEdit', if the cell is "Refresh":
a)Empty out the document cache
b)Fill doc cache with external data (a table in my case)
c)For all cells with my 'getStockoData(...' custom function
get the formula
set '=0'
set the fromula
d)Set the cell in (1) with a value of "Ready"
This does refresh the bits you want BUT IS NOT FAST.
I followed this video, from 1:44, and this worked for me.
You should use a specific update function, initialize a "current time" variable and pass this permanently updated variable to your custom function. Then go to Triggers and set up an "every-minute" time-driven trigger for the update function (or choose another time interval for updates).
The code:
function update() {
var dt = new Date();
var ts = dt.toLocaleTimeString();
var cellVal = '=CustomFunction("'+ ts + '")';
SpreadsheetApp.getActiveSheet().getRange('A1').setValue(cellVal);
}
Just add GOOGLEFINANCE("eurusd") as an additional argument to your custom function, like:
=myFunction(arg1, arg2, GOOGLEFINANCE("eurusd"))
As #Brionius said put an extra dinamic argument on the function. if you use now() you may have timeout problems make the update a little bit slower...
cell A1 = int(now()*1000)
cell A2 = function(args..., A1)
If you have written a custom function and used it in your spreadsheet as a formula, then each time you open the spreadsheet or any referencing cell is modified, the formula is recalculated.
If you want to just keep staring at the spreadsheet and want its values to change, then consider adding a timed trigger that will update the cells. Read more about triggers here

Merge Form Submission to document - lost newbie

Seeking guidance on the following:
User submits Formstack form -> Form entry populates a row on Google Spreadsheet -> Trigger the execution of a document merge for that submission (now a ROW in the sheet) with the column header defining the variables -> Email merged document to User via submitted email address.
My document requires the ability to conditionally handle many of the variables (if/then conditional text based on form response). I've played with an App called Ultradoc which seems great for the variable handling in the Google Document, supports conditions, etc.
However, the problem is it doesn't know how to select one ROW of data, rather it's designed to run a merge for everything in each column.
One idea might be to run a script which takes that new ROW and somehow makes it look like a two row sheet (header+submitted row)?? Somehow hides the other rows? This seems terribly kludgy. What's the right way to approach something like this?
Thanks in advance
You actually don't need any third party apps for this.
Create the form as a Google Form, create the script and make it run on Form submit.
To get the values that were entered into the form, pass the form submission as a parameter to the function: function processForm(e){
To get the data in the form, access the e.values array. It's zero indexed, starting with the top item on the form.
Store the submitted data into variables
var name = e.values[0];
var email = e.values[1];
// and so on...
Perform any validation or document handling.
Create a copy of your template document
var copyId = DocsList.getFileById("templateDocID")
.makeCopy(docName+' from '+name) //or whatever you wanted to call the resulting document
.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
Replace the text in the template
copyBody.replaceText("NAME", name);
copyBody.replaceText("EMAIL", email);
// and so on...
Send the document to the user (for my application, I sent as pdf, but you can send it how ever you like)
copyDoc.saveAndClose();
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
MailApp.sendEmail(email, copyDoc.getName(), "Here's your document", {attachments:pdf});
DocsList.getFileById(copyId).setTrashed(true);

google script reject spreadsheet submit

I have a function in a spreadsheet based script that is triggered when a submission is made with the spreadsheet form :
function onEntry(e){
Logger.log(e);
MailApp.sendEmail("scriptadmin#uniben.edu", "New Mail Request", "Someone submited data");
}
How can I reject the entry, say if it's a duplicate entry ?
Using the documentation on events you will have to choose what data you want check (user name, specific field...) and compare that to data already in the spreadsheet.
You should do these iterations on an array level since it will be far more efficient and fast, you can get data in an array using something like
var data = SpreadsheetApp.openById(key).getDataRange().getValues();
You could also use javascript function like indexOf() that will return -1 if no match if found or item position in the array if a match is found.
Actually there are many ways to do that but your question is too vague to know what will be the best...
EDIT : following your comment, I'd suggest you let the duplicate form data come into the sheet and then use a script to remove duplicates. You could run this script on a on form submit trigger or on a timer to let it run daily or hourly, and send the email only if the last entry was a new one (no duplicates found)... depending on your use case.
There is a script in the gallery that does the job pretty well, it was written by Romain Vialard, a GAS TC that has contributed a lot. (the link above goes to the script description but you can get it also in the public gallery, just search for 'remove duplicates' you'll see that other scripts do that, all the scripts in the gallery have been checked by the GAS team)
4 months late, but better late than never. I believe this function does almost what was originally requested. i.e. "How do I prevent the entry from entering the spreadsheet if I decide that it's a duplicate." It is not precisely what was requested, but very close.
This code checks one column against that same column in another sheet, for all rows in that sheet. Lets say you have a list of companies or clients on a sheet. That list includes name, phone, address, etc. etc. Lets say you want to check against the phone number - if the phone number you are currently entering is already on your client sheet, then don't allow entry - or more precisely clear it out immediately upon entering it.
I'm sure the more experienced members will be able to point out flaws, but it works for me.
I believe it will also work for the case where a phone number in the middle of the sheet is changed - so it's not just last line that gets checked, it's the line that gets edited that gets checked - I've not tested this particlar scenario. Also, I made some changes to variable names to protect the innocent...hopefully I didn't mess anything up while doing that.
I call this function from within another function that is triggered by onEdit. Theoretically it should be able to be installed as an onEdit trigger itself. I hope someone finds it useful.
function checkNewEntryForDuplicate(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entrySheet = SpreadsheetApp.getActiveSheet();
var clientSheet = ss.getSheetByName("Clients");
var r = entrySheet.getActiveCell();
var lastCol = entrySheet.getLastColumn();
// If this had any consistency, we'd be able to get the row from entrySheet the same
// as we get column. But there is no getRow() method at the sheet level.
var rowNum = r.getRow();
var clientData=clientSheet.getDataRange().getValues();
var phoneColumnOffset=getPhoneColumnOffset(); // You'll need to get the offset elsewhere. I have a function that does that.
var columnNum=e.range.getColumn(); // column that is currently being edited
if (columnNum != phoneColumnOffset+1) // no point in doing anything else if it's not the column we're interested in.
return 0;
var entryRow=entrySheet.getRange(rowNum, 1, 1, lastCol);
var phoneNum = e.range.getValue();
// iterate over each row in the clientData 2-dimensional array.
for(i in clientData){
var row = clientData[i];
var duplicate = false;
// For each row this conditional statement will find duplicates
if(row[phoneColumnOffset] == phoneNum){
duplicate = true;
var msg="Duplicate Detected. Please do not enter. Deleting it..."
Browser.msgBox(msg);
entryRow.clearContent();
entryRow.clearComment();
return duplicate;
}
}
return duplicate;
}
I am doing the same things but having no scripts at all and just by spreadsheet functions. That kind of things are just like SQL for me and very interest to do.
For your question, this link will help: http://www.labnol.org/software/find-remove-duplicate-records-google-docs/5169/

GAS passing variables to time based triggers

I have a Google spreadsheet with an onEdit() trigger to create a second time based trigger.
Simply: when the status column is edited to 'Approved' a trigger is created to send a feedback email on a supplied project completion date.
var oneTimeOnly = ScriptApp.newTrigger("emailFeedback").timeBased().at(endDate).create();
I wish to pass a variable to the second trigger. I could create Project Property or add a column in the spreadsheet. However it would be simpler to pass the variable when creating the trigger.
When I insert any additional characters inside the newTrigger quotes this causes the entire contents of the function to be stored in the trigger (which subsequently fails).
var oneTimeOnly = ScriptApp.newTrigger("emailFeedback<strong>(regEmail)</strong>").timeBased().at(endDate).create();
.
Is there a way to store a variable inside the trigger?
Using ScriptDB and new Function(), I was able to create a method for creating dynamic trigger functions.
The gist of the solution is to store the code you want to trigger is the db with the parameters you want to pass:
"myFunction('Hello world')"
Then, when the script starts, as a global variable, you attach newly created functions from your ScriptDB. (I've done this dynamically in my link below.)
globalFunctions.callThisOne = new Function("e", "myFunction("Hello world"));
Finally, when you create your trigger, you created it using the globally accessible function as such:
ScriptApp.newTrigger("globalFunctions.callThisOne").timeBased().everyDay(1).create();
I have written up a short post about this and posted the source. Hopefully it's useful.
You can read more about it here: http://goo.gl/wbUqH6
Or see the code here: http://goo.gl/zjUiYe
Sorry, there is not a way to do this.
As I understand correctly, the question was how to pass data to a time triggered function in a google script project. Eoin described a situation, but you may facing to many.
A classic situation when your script proccesses a complex spreadsheet that may run for long minutes. As you may probably know each script has about 6 minutes runtime limit. This situation you should break your script smaller logical partitions and at the end of each one can create a new trigger for the next part. Okay, but the next part must know about some data of the current running script's variables. Because no way to pass these data via newTrigger() you can create a snapshot and put into the script property context in a serialized way.
An easy way to do by ScriptProperties.setProperty().
Use ScriptProperties.setProperty() to store serialized parameters that can be accessed by trigger method.
#user2166613 is right, but a bit short. Here is how to do it.
I show an example that uses an after() trigger. This is a really interesting use case, as it allows to decouple time consuming tasks from e.g. web app calls, so the calls return control immediately and the processing is done in the background.
In my example I adapt the column widths of a sheet in a function that this run delayed.
// call this function to set a time based trigger and transfer parameters
function setTimeTrigger_AdaptColumnWidths() {
var ssId = SpreadsheetApp.getActiveSpreadsheet().getId();
var wsId = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getSheetId();
var scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty('spreadsheetId', ssId);
scriptProperties.setProperty('worksheetId', wsId);
// Delay 10 secs, but real execution time may vary up to 15 min!
ScriptApp.newTrigger('adaptColumnWidths').timeBased().after(10000).create();
}
// this function is called by the trigger
function adaptColumnWidths() {
var scriptProperties = PropertiesService.getScriptProperties();
ssId = scriptProperties.getProperty('spreadsheetId');
wsId = scriptProperties.getProperty('worksheetId');
// getSheetById() is a custom function – see below – not yet in Spreadsheet Class!
sheet = getSheetById(SpreadsheetApp.openById(ssId), wsId);
// now do what we want to do in the timeBased trigger
for (var i = 1; i <= sheet.getLastColumn(); i++){
sheet.autoResizeColumn(i);
}
}
// -----
// custom function – hopefully this will become a method of Spreadsheet Class any time soon
function getSheetById(ss, wsId) {
var sheets = ss.getSheets();
for (var i=0; i<sheets.length; i++) {
if (sheets[i].getSheetId() == wsId) return sheets[i];
}
}
Please be aware that your are storing in a dataspace here that is common to all your function calls. So multiple calls in a short time can overwrite each others parameters.
In my use case this is not a problem as the spreadsheet and the worksheet will not change. But do NOT try to transfer data that can change from call to call.
The real moment of execution can vary up to 15 minutes (no matter what exact time you ask for), so there is plenty of room for multiple function calls to interfere with each other!!!