importdata undefined within googlescript - javascript

I have a Google Sheet where I am tracking various asset prices including crypto.
The easiest way to get crypto prices is by importing from cryptocurrencies.cc:
=importdata("https://cryptoprices.cc/AION/");
However, now my spreadheet is full of references to the cryptoprices.cc website. If it ever goes down or changes domain, I would have to replace the URL everywhere in my sheet, which is quite uncontrolled. So I thought about making a wrapper function:
function cryptofinance(token) {
return importdata("https://cryptoprices.cc/"+ token);
}
This returns an #Error! however: ReferenceError: importdata is not defined (line 94). I am assuming that you cannot call Google Sheet functions outside of the context of the Sheets cells, correct?
If not, what is the proper way to call importdata from within this function?
If yes, then what is the best alternative to retrieve the same information using javascript?

You cant use importdata like a formula at this place.
first you need to get cell refernce then
you need to put formula inside the setvalue() function;
var currentCell = SpreadsheetApp.getCurrentCell(); // Select cell here
currentCell.setValue('=importdata("https://cryptoprices.cc/"+ token)');
for select a range of cells you can use getRange() function
SpreadsheetApp.getRange(row,col).setValue('=importdata("https://cryptoprices.cc/AION/")');
change row, col with cells range.

Related

Google Sheets Scripts: Can you get a range from a rangeId?

My google sheet has a cell on sheet1 that contains a link to a cell on sheet2. In my function, I am able to get the link url, but cannot figure out how to get a range from the rangeId:
var link = generatorSheet.getRange(currRow, 2)
var linkUrl = link.getRichTextValue().getLinkUrl()
Logger.log(linkUrl) // linkUrl = "rangeid=1843553975"
I've tried using getRangeByName and various other functions but keep getting a null value back, not a Range object.
Thanks in advance!
Edit: My overall goal in this is to iterate over each row in sheet1, where each cell in column 2 links to a cell in sheet2. I need to take the value from the cell in sheet2 and copy it into sheet3. In sheet1, there's a check box in column 1 of each row, so that's what I'm using to determine whether or not the linked to value will be copied. I'll have a button to kick off my function and populate sheet3, and it has to assume these links are already in place - they were done by hand prior
When you create an hyperlink to a range using the user interface, you are facing this issue. I think you may have to change the way of designing the hyperlink and try to define it by the formula
=hyperlink("#gid=123456789&range=A2","go to ...")
and then you will retrieve the range by
Logger.log(linkUrl.match(/(?<=range=).*/g))
For documentation purposes,
This is a url hash fragment:
#rangeid=1843553975
The id seems to be created, when inserting a link to a range using the user interface. This is distinctly different from a namedRange When clicked, it's appended to the url in the browser, i.e.,https://docs.google.com/spreadsheets/id/edit#rangeid=1843553975. Once appended, through onpopstate javascript event, the range linked to the id is highlighted in the browser/app.
NamedRanges has a similar workflow. It also provides a rangeid=<10 digit ID>. But, it also has a name attached to it. But even in this case, the rangeid is not retrievable, though Sheets API provides a obfuscated range id.
There was a feature request made to Google, but it was made obsolete, because of lack of response on the part of the requestor:
https://issuetracker.google.com/issues/162810351
You may create a new similar issue there with a link to this answer. Once created, link the issue here.
Other related trackers:
https://issuetracker.google.com/issues/129841094
https://issuetracker.google.com/issues/134986436

Custom Google Sheet Function Updating Without Any Cause

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

Logical paradox - custom function - parameters are coming from another fucntion

I hope I can make this makes sense....
I have gone through a bunch of other functions to end up with a variable that contains the data selected by a user from a drop down list on a sidebar to my google sheet.
The final function that that variable is sent to is like this:
function processFormResponse(formObject ){
reportMonth = formObject.chosenReport;
//result of reportMonth is a string. Example "Report_Nov 2017"
}
So now I have a variable called reportMonth that has what I need. But now, I want to write a vlookup that will select the same range every time but on a different sheet depending on the user selection (reportMonth).
From what I have researched, I cant use variable inside the vlookup, so I was going to write a custom function that does the lookup for me.
But here's my paradox: I cant use processFormResponse as my custom function because it has the formObject already inside its parameters because its already receiving information from the previous function and I cant do a separate function because I can't seem to get reportMonth to be global... (I with and without var)
I basically something like this:
=IFERROR(VLOOKUP($E3, reportMonth !$F:$J,2,false),"")
As mentioned in the Google Apps script documentation:
For the Range object:
setValue(value)
Sets the value of the range. The value can be numeric, string, boolean or date. If it begins with '=' it is interpreted as a formula.
So, if you have a 1-cell Range (a.k.a. a block of cells), then you could run
range.setValue("=IFERROR(VLOOKUP($E3,"+reportMonth+"!$F:$J,2,false),"")");
For Reference: https://developers.google.com/apps-script/reference/spreadsheet/range#setvaluevalue

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.

How to implement query function to use Google spreadsheet as a database?

I'm trying to use a spreadsheet as a database, where each sheet would be a table and the name of a person is used as a primary key (It seems not to be the best solution, but the good spreadsheet interface makes me prefer this solution rather than trying to use ScriptDB.)
And I want to do the following: When you select a name on a sheet and press a button on the menu I added, a function performs a search in another table and a screen and shows all the results of that query in the other table, showing properties records that only that table contains (later I want to add the possibility to generate a text file from a GDocs template).
My questions is:
1) Considering this screen/panel UI has a variable length (because the record number may vary in other tables), what is the best way to create this panel/UI in Google Apps Script? (I don't want to use the Logger.log because I want to add a button to convert the query into a file)
2) In addition to this solution (a search in the resulting 2D array):
function test(){ // to test the find function with an argument, 'any' in this case
var result = findItem('any');
if(result){Logger.log(result.getA1Notation())}else{Logger.log('no luck !')};
}
function findItem(item){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = ss.getDataRange().getValues()
for(var n = 0;n<data.length;++n){
if(data[n].indexOf(item)>-1){ // this is a "strict" find, ie the value must be the entire search item. If you want to do partial match you should compare differently...
return (ss.getRange(n+1,data[n].indexOf(item)+1)); // if found return the range. note the +1 because sheets have 1 index while arrays have 0 index
}
}
return false;// if we come to the end of sheet without result...
}
There is an alternative method to perform queries like this?
THANKS for any help!
Create a UI instance. Then a scrollable panel inside a main panel is the best way of doing this and then using array's to search through the data. I typically create header body and footer panels with the body being scrollable

Categories