Custom Google Sheet Function Updating Without Any Cause - javascript

I'm using a custom function to pull price data for EVE Online and I would only like the function to update upon a specific cell change. Instead it's updating every ~10-20 minutes which is using up a ton of my daily quota for URL Fetches.
Looking below you can see the main function is in a page labeled "Warehouse Stock". It pulls all price data for items in the "Item" column. The cell refreshes with a custom function that changes cell B4 in the utility sheet. When that cell changes it updates the values in the custom function because of the IF/THEN statement. Lastly the prices are loaded into the main sheet and sorted by the "product" column.
Also I have recalculation "On Change" and Iterative Calculation turned off.
Thank you for reading and any help you can provide.
The custom function is:
/**
* Query's Fuzz market API for the given types
* #param {range} A vertical range of type_ids.
* #return maxBuy and minSell for each type_id
* #customfunction
*/
function fuzzApiPriceData(type_ids) {
if (!type_ids) throw 'type_ids is required';
const ids = Array.isArray(type_ids) ? type_ids.map(id => id[0]) : [type_ids];
const fuzz_price_data = JSON.parse(UrlFetchApp.fetch(`https://market.fuzzwork.co.uk/aggregates/?station=60008494&types=${ids.join(',')}`));
return [['minSell', 'maxBuy']].concat(type_ids.map(type_id => [parseFloat(fuzz_price_data[type_id]['sell']['min']), parseFloat(fuzz_price_data[type_id]['buy']['max'])]));
}

i think there's a fairly basic misunderstanding here.
"Custom functions" are designed to be written in cells on a sheet. they are by there nature designed to run ALL the time, constantly updating.
If you are attempting to run a custom script, you do that from the script editor itself, you don't even write the function in a cell at ALL.
I'm assuming you didn't write the "custom function" you're using(?) So it will be a bit difficult (but not impossible!) to convert it to a script that writes to a certain place on the sheet at a certain time. But you might research a bit more about the difference between custom functions designed to be executed in cells, and scripts designed to be run on a time trigger.

Regarding you answer:
I would like the function to refresh everyday, aswell as having the option to manually refresh the function by the contents of the cell Utility!B4
I propose you to use Installable Triggers:
Time-driven trigger: It can execute a function each day at specific time.
Installable edit trigger: It can execute a function when a certain value in a specific cell changes.
However, if you want to execute a function manually, I recommend you to insert a drawing and assign a function to it.
Reference
Installable Triggers
Clickable images and drawings in Google Sheets

What I usually do for that is : put a checkbox in a cell. Then, when calling your custom function, add an extra reference to that cell, even if the parameter is not included in your custom function. Each time you will switch true/false, your custom function will be reactivated. Then you can also define another function with a trigger that just change the value of true/false. Here is an example in sheet 'Data' cell A3 : the function is getDataJSON(C1,A2:U2,A1) with A1 even if the custom function take into account only the first and second parameter. https://docs.google.com/spreadsheets/d/1DN0Gfim0LC098zVgrUpt2crPWUn4pWfZnCpuuL1ZiMs/edit?usp=sharing

Related

Tabulator.js table elements retrieve the index of the row and serve as a control element to other plots

I am using tabulator package 4.3.0 to work on a webpage. The table generated by the package is going to be the control element of a few other plots. In order to achieve this, I have been adding a dataFiltered function when defining the table variable. But instead of getting the order of the rows in my data object, I want to figure a way to get the index of the rows in the filtered table.
Currently, I searched the manual a little bit and have written the code analogue to this:
dataFiltered: function(filters,rows){
console.log(rows[0]._row.data)
console.log(rows[0].getPosition(true));
}
But the getPosition always returned -1, which refers to that the row is not found in the filtered table. I also generated a demo to show the real situ when running the function. with this link: https://jsfiddle.net/Binny92/3kbn8zet/53/.
I would really appreciate it if someone could help me explain a little bit of how could I get the real index of the row in the filtered data so that I could update the plot accordingly and why I am always getting -1 when running the code written in this way.
In addition, I wonder whether there is a way to retrieve the data also when the user is sorting the table. It's a pity that code using the following strategy is not working in the way I am expecting since it is not reacting to the sort action and will not show the information when loading the page for the first time.
$('#trialTable').on('change',function(x){console.log("Yes")})
Thank you for your help in advance.
The reason this is happening is because the dataFiltered callback is triggered after the rows are filtered but before they have been laid out on the table, so they wont necessarily be ready by the time you call the getPosition function on them.
You might do better to use the renderComplete callback, which will also handle the scenario when the table is sorted, which would change the row positions.
You could then use the getRows function passing in the value "active" as the first augment return only rows that have passed the filter:
renderComplete: function(){
var rows = table.getRows("active");
console.log(rows[0].getPosition(true));
}
On a side note i notice you are trying to access the _row property to access the row data. By convention underscore properties are considered private in JavaScript and should not be accessed as it can result in unstable system behaviour.
Tabulator has an extensive set of functions on the Row Component to allow you to access anything you need. In the case of accessing a rows data, there is the getData function
var data = row.getData();

Display value form rows marked in spotfire visualization?

After marking in a visualization i want to capture a particular column value form rows marked and display it in text area .
thanks
The way to do this is to add a data function to the analysis. Define the function as a identity function, i.e.:
output <- input
This can be an R function or TERR function. If you use TERR it can execute locally rather than going to stat services (though web player will need to use stat services anyway).
Now, connect the data function to your analysis and as input you make it depend on the current marking. Assign a value to the input parameter by creating an aggregation on the column with the value you are looking to collect.
Assign the output of the data function to a document property.
The image linked here shows a sample of how to configure the input parameter:
Sample input parameter config
To show the result in the text area you create a normal property control of your choice in the text area, and attach it to the document property that is written to by the R/TERR script.

function recalculates every time i open the sheet, I only want it to recalculate on edit

function timestamp() {
return new Date()
}
The function recalculates every-time i open the sheet. i only want it to recalculate on edit.
I have tried to mess with "onEdit" but i can never get it to work. I have also tried the "current project triggers" but that doesn't seem to fix the problem. I apologize that for the simplicity of the question, I simply can't find or figure out the answer.
Google sheets script
https://docs.google.com/spreadsheets/d/1-Ix9LUmMYNqWnz0mB2PAg9ocJ-TwszqHRbqxAchcxhc/edit#gid=0
It looks (based on your comments on the question), like you've created a custom formula and put it in a cell. If that's the case (meaning that you actually have =timestamp() in a cell), then it will always recalculate both on open and on edit.
That's just how formulas (both the standard ones and custom ones) work. You'll notice this when you have start to have too many formulas in a spreadsheet and it starts to slow down, or even not load correctly.
If you want something that only updates on edit, you'll have to write a function that does exactly that, then set a trigger that calls it on edit.
For example, this function will put the current date in cell A1 of the first sheet of the current spreadsheet:
function setTimestamp()
{
var thisSS = SpreadsheetApp.getActiveSpreadsheet();
var firstSheet = thisSS.getSheets()[0];
var firstCell = firstSheet.getRange(1, 1);
firstCell.setValue(new Date());
}
This kind of function will only run when you call it, so you can set the trigger to whatever you want. Obviously, you'll have to figure out how to select the cell where you want the date to appear.

How can I call a function all the time in a Google Spreadsheet cell?

Here is my problem:
I created this function on Google Script:
function LASTCOLELEMENT(colIndex) {
// Gets the whole SpreadSheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var registerSheet = ss.getSheetByName("Registro de Inventario");
// Returns the last element of the colIndex column
return registerSheet.getRange(registerSheet.getLastRow(), colIndex).getValue()
}
And I called it in my spreadsheet as:
=LASTCOLELEMENT(1)
The output is correct and it gives me what I want, but as soon as I add a row to "Registro de inventario" sheet, "=LASTCOLELEMENT(1)" still shows what was being showing before because it hasn't been called again.
If I delete "=LASTCOLELEMENT(1)" and re-write it again it shows the last element.
I've been thinking about it for a while and I don't know how to fix this.
Google sheet caches the result, and thus does not recall your function and does not refresh the data, because the formula parameter (1) does not change, so google inferes that the result does not change neither; eventhough the data that is being used does change, but that is beyond the google sheet inspection.
You might either get used (or educate your users) to make a manual refresh (with Ctrl-R)
Or force a data reload with a trick. Add an unused parameter to the function function lastColVal(colindex,fakecell) and pass a reference to a cell =LASTCOLVAL(1,$A$1). Eventhough your function does not use this value, its mere presence will make google sheet to refresh the data. Then, to force the refresh every time you add a row, change the value of the A1 cell, for example, with a COUNT of nonblank cells.

Function for last modified date of cell

I have a function written in VBA that does what I want it to (see below. note: I did not write this function myself)
What I wanted was to a function, say, "=LastModifiedDateOf(CELL)", where CELL, is a parameter that indicates the cell I want to monitor. If the value of such cell ever gets changed, the cell containing the function has its value updated to the current date.
Ultimately I want a function written in google sheets that does the same thing, but I dont really understand how this function works.
Can anyone do one or both: 1) Explain whats happening in the function below, 2) Write a function in googlescripts (js) that does the same thing?
Public Function Lastmodified(c As Range)
Lastmodified = Now()
End Function
1) Explain whats happening in the function
Spreadsheet cell contents are recalculated only when the content of their references change. When you think about it for a bit, this makes sense for efficiency: it would be a waste of computer resources to calculate a new value for a cell when none of the referenced values (aka parameters) has changed... we'd just end up with the same value.
The magic for the VBA function you've provided is that the cell containing it gets recalculated only when the referenced cell is changed. That is under the control of the spreadsheet, and is completely independent of the script itself.
The same behavior is exhibited in Google Sheets. And in both cases, it's not important to the function what the monitored cell is - the function just returns the current time whenever it is called, which should be at times when the cell's value changes.
However, there are other reasons for the function to be called. In Excel, you can manually trigger spreadsheet recalculation, and that would update this function's output anywhere it appeared in the spreadsheet, with the current time. Likewise, in Google Sheets, any time you load the spreadsheet you could trigger a recalculation.
2) Write a function in googlescripts (js) that does the same thing
/**
* Return the time that the referenced cell or range was last changed.
* Initial use shows current time.
*
* #param {Sheet3!B32} reference Cell or range to monitor.
* #returns The time the reference was last changed.
* #customfunction
*/
function lastModified( reference ) {
// Surprise - we don't actually care what has changed!
return( new Date() );
}
In this snippet, if A1 cell is modified, the cell A2 is automatically updated with the modification date.
function onEdit(e) {
if (e.range.getA1Notation() === "A1") {
e.source.getRange("A2").setValue(new Date());
}
}

Categories