Limit the frequency of calls to onEdit - google-sheets

I wrote some scripts using the script editor to automate some google spread-sheet tasks.
I would like to do a few things after the user interacts with my users sheets, .e.g update some background sheets that start with _.
I wrote the following:
function onEdit(e){
var range = e.range;
if (e.source.getActiveSheet().getName()[0]!='_'){
//It is an user edit!
UpdateOtherHiddenTables()
}
};
My problem is that UpdateOtherHiddenTables() takes quite a while, like 2 mins, and it is triggered on any user edit so it is not ideal.
How would you make sure that after a user has interacted with a sheet, that UpdateOtherHiddenTables() is called, but not too often?

I would use Script properties in combination with a timed trigger. The on-Edit trigger only records the fact that the Spreadsheet was edited:
function recordEdit() {
var sp = PropertiesService.getScriptProperties();
sp.setProperty("edited", "yes");
}
This function needs to be run by an installable trigger, simple onEdit won't provide the authorization necessary to modify script properties.
The UpdateOtherHiddenTables function is set to run every 10 minutes, or every hour, or whatever interval you want. It checks whether a refresh is needed.
function UpdateOtherHiddenTables() {
var sp = PropertiesService.getScriptProperties();
if (sp.getProperty("edited") == "yes") {
// update stuff
sp.setProperty("edited", "no");
}
}
By the way: onEdit is only triggered by user edits. A script changing the values in a spreadsheet will not fire that trigger.
I'm using string values instead of Boolean, because Properties stringifies everything. Storing false gets you back the string "false", which is truthy...

Related

Make a cell in google sheets automatically 'insert comment'

I don't think I explained it well, column L is where I can log what I have done - with a date and time, so say I send a message, I would log MESSAGE SENT then say I make a call I could log CALLED and any info I wanted to remember - each entry being date and time stamped
In the image you can see the comment field - all i want is that to pop up when I click on the cell and be able to add to the comment field
You can use the onSelectionChange(e) trigger and check if the selected cell(s) fall into your criteria, if so then insert comment.
https://developers.google.com/apps-script/guides/triggers
You could use this sample script to set a comment on an edited cell:
function onEdit(e){
var range = e.range;
range.setNote('Last modified: ' + new Date());
}
However this requires that you edit the content of the cell to trigger the onEdit() function. Which you can modify instead to trigger the function manually (or assign the script to an image to act as a button) like so.
function setComment() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.getRange('L14:L16').setNote('Last modified: ' + new Date());
}
Reference:
https://developers.google.com/apps-script/reference/spreadsheet/range#setNote(String)
https://developers.google.com/apps-script/guides/triggers#onedite

Viewers (per Link) jump to current date when they open file

I have a table in Google Sheets in the format:
A B C
Day Date inventory demand
Day2 Date2 inventory demand
etc.
Others are required to fill in inventory and demand every day. Thus, it would be helpful if they open the sheet they jump always to the current date. This could be done over HYPERLINK or code. However, as I am informed onOpen works for the editor, however not for viewers. As this is currently the case. When I open the file I jump to the current date, however people viewing and editing the file per link do not.
Could somebody please help me? Thank you.
I also do not understand, why creating a cell that jumps to the current date as an alternative does not work.
I tried various variations of
=HYPERLINK("l i n k&range=B"&MATCH("TODAY",B1:B1500,0),"Jump to today")
or
=HyperLink("LINK&range=B" &Match(Today(),B6:B,1),"JUMP to Today")
// jump to current date
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange("B:B");
var values = range.getValues();
var day = 24*3600*1000;
var today = parseInt((new Date().setHours(0,0,0,0))/day);
var ssdate;
for (var i=0; i<values.length; i++) {
try {
ssdate = values[i][0].getTime()/day;
}
catch(e) {
}
if (ssdate && Math.floor(ssdate) == today) {
sheet.setActiveRange(range.offset(i,0,1,1));
break;
}
}
}
try like this:
=HYPERLINK("#gid=0&range=B"&MATCH(TODAY(); B6:B; 0)+5; "zu heute")
I found the options: Edit Triggers
To manually create an installable trigger through a dialog in the script editor, follow these steps:
From the script editor, choose Edit > Current project's triggers.
Click the link that says: No triggers set up. Click here to add one now.
Under Run, select the name of function you want to trigger.
Under Events, select either Time-driven or the Google App that the script is bound to (for example, From spreadsheet).
Select and configure the type of trigger you want to create (for example, an Hour timer that runs Every hour or an On open trigger).
Optionally, click Notifications to configure how and when you are contacted by email if your triggered function fails.
Click Save.
Google Explanation

How to force refresh URL data in Google Sheets?

How to fetch data every two minutes from an URL, tried different methods to achieve this, couldn't succeed.
=if(Minute(Now())=Minute(Now()),
ImportHtml("https://www.nseindia.com/live_market/dynaContent/live_watch/option_chain/optionKeys.jsp?symbolCode=-10006&symbol=NIFTY&symbol=NIFTY&instrument=-&date=-&segmentLink=7&symbolCount=2&segmentLink=17",
"table",1),"")
Tried above formula, still not updating data.
Need help on this.
this could do the trick... put =NOW() in some cell and setup an update rate in settings:
function getData() {
var sheetName = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("<sheet-name>");
var queryString = Math.random();
var cellFunction = '=IMPORTHTML("<url>?","table",<index>)';
sheetName.getRange('<import-cell>').setValue(cellFunction);
}
Replace with the name of your sheet (the tab name, not the name of the file).
Replace with the URL of your web page.
Replace with the table position on the page, e.g. 1.
Replace with the cell where you want to put your import statement, e.g. A1.
Now make a trigger for getData() to run in each minute.
It will write the IMPORTHTML command every time in the cell in every minute.

Google Script can't call Twitter API when using onEdit()

I am trying to write a script which will pull data from twitter's API each time I edit a cell. The demo code I currently have looks like this:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Candidates");
function onEdit(e){
var rng = e.range;
// Check to make sure it is a single cell in specific column that was edited
if(rng.getColumn() == 1 && rng.getNumRows() == 1 && rng.getNumColumns() == 1){
callTwitter(rng.getRow());
}
}
/* --- ---------------------- --- */
/* --- Compare with core list --- */
/* --- ---------------------- --- */
function callTwitter(cRow){
var cRow = 2; // placeholder for testing
var twitterService = getTwitterService();
var response = JSON.parse(twitterService.fetch('https://api.twitter.com/1.1/users/lookup.json?screen_name=' + sheet.getRange(cRow, 1, 1, 1).getValue()));
sheet.getRange(cRow,2,1,1).setValue(response[0].screen_name);
}
What I've checked
I have confirmed that onEdit() gets called when I edit a cell and it does pass through the variable to the callTwitter() function.
Running the callTwitter() function on its own returns the desired result (pulls username from column A, queries twitter API and returns display name in column B).
The issue
The callTwitter() function always fails when I call it via the onEdit call. It stops right before the following line of code.
var response = JSON.parse(twitterService.fetch('https://api.twitter.com/1.1/users/lookup.json?screen_name=' + sheet.getRange(cRow, 1, 1, 1).getValue()));
My current assumption is that the onEdit call is somehow clashing with the API call, but I can't seem to find out why or how to solve it.
--
I have been trying to debug this for hours now and any help or direction on where to look would be very helpful.
Code not included here is the Twitter OAuth which I copied from Google's example https://github.com/googlesamples/apps-script-oauth1
Simple triggers like onEdit won't work in this scenario. According to the documentation,
They cannot access services that require authorization. For example, a simple trigger cannot send an email
because the Gmail service requires authorization, but a simple trigger
can translate a phrase with the Language service, which is anonymous.
You must use an installable trigger.
https://developers.google.com/apps-script/guides/triggers/installable
Create the fuction that you need to execute on edit, go Edit -> Current project's triggers, and select 'From spreadsheet'-> 'On edit.

Google Script: Have an onEdit timestamp static

I'm trying to have a timestamp appear in a column whenever data is added to a sheet. I've had some success with the following script:
function onEdit(e) {
var colToWatch = 2, colToStamp = 1;
if (e.range.columnStart !== colToWatch) return;
var writeVal = e.value ? new Date() : '';
e.source.getActiveSheet()
.getRange(e.range.rowStart, colToStamp)
.setValue(writeVal);
}
My issue is, every time the text in col 2 is edited, the timestamp changes to the current time.
My hope it to have a timestamp that shows when the text was originally added (so it can be organized by that date in another sheet). Other people will have access to this sheet and may change something by accident and cause changes in the sheet organized by date.
I'm new to scripting, is it possible to have an onEdit only run the first time data is added? It seems like onChange() might be able to help me, but I haven't been able to find anything.
Basically you want to terminate if the timestamp cell is already filled.
if (e.source
.getActiveSheet()
.getRange(e.range.rowStart, colToStamp)
.getValue()) {
return;
}

Resources