I am creating a custom function which processes strings held in cells on a sheet. How can I access the strings from within the function in a common way even if the function is given a range or a list of cells or a combination?
e.g. calling the function myFunction(A1:B2) or myFunction(A1,A2,B1,B2) or even myFunction(A1:A2,B1,B2) etc.
Do I need to determine inside the function how it has been called and combine all the different cell/range contents or is there a Google sheets api that can resolve all possible calls into a single range?
Thanks
Just use .flat:
function myFunction(...args){
const input = args.flat(2);
//do stuff with input
}
Related
I am new to google scripts and I am having trouble with passing parameters from my google spreadsheet to my google script.
I have created a function in my script:
function functionname(ref) {
Logger.log(ref);
var value = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(ref).getValue();
//do stuff with the value read from the sheet
return modified_value;
}
and I am calling it in my google spreadsheet like:
=functionname(A4)
(the function is called from an empty A5 cell, with cell A4 filled with text).
I have initially tried with a static reference in the function, like:
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("H9").getValue()
In this situation, it worked perfectly, but I do not want to replicate the function for each cell I need to operate, given I need to deliver this to non-programmers and the list of cells will increase.
Initially, I read that passing the parameters from the cell will be sufficient to receive the value and I had tried also this solution. Still, no matter what I try, the value of ref is always "undefined".
Can anyone please help me understand what I am missing?
Thanks
No need for the SpreadSheetApps methods for custom function to pull the value from the SpreadSheet because it already gets the cell value that you are referencing. Just remove the var value = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(ref).getValue();
function functionname(ref) {
Logger.log(ref);
//do stuff with the value read from the sheet
return modified_value;
}
You can call this function directly on your spreadsheet. Don't forget to store the new value on a variable and return it, or return the computed value directly.
I have written a custom google apps script function that is being called by a google sheet. In this function an API is called and the result of this API is being returned so that it gets displayed in the calling cell of the google sheet.
My problem now is that the sheet calls this function everytime I open the document and there are over 80.000 cells with this function.
Is it possible to save the returned value to the cell and don't call the custom function again when an value has been returned? I want the function being called only once per cell, even if I close the document and reopen it. The returned value should be saved until something else is being written into to cell. That would make my sheets document much more usable than the current state.
From the question
Is it possible to save the returned value to the cell and don't call the custom function again when an value has been returned? I want the function being called only once per cell, even if I close the document and reopen it. The returned value should be saved until something else is being written into to cell. That would make my sheets document much more usable than the current state.
By solely using the custom function it's not possible. There isn't a straight forward solution is to achieve this, in order to keep things simple you should look for another way to implement what is being done by the custom funtion.
One option is to use a trigger (including a custom menu / a function assined to a drawing) to check if the cell that should have the value returned by the custom function is empty and in such case fill it with the corresponding value. The best trigger to use will depend on your spreadsheet workflow.
As specified by Ruben this is not possible, with a custom function.
In my particular case I have resorted to using an Apps Script function that is triggered by an edit event of the spreadsheet and verifies if the event is in the column where the function that I want to execute only once should be, later replacement its content with the result of calling the API.
function freezeValue(e) {
var rangeEvent = e.range;
var col = rangeEvent.getColumnIndex();
if (col === 2) { #Verify column of event
var value = rangeEvent.getValue();
/*Call your api*/
result_api = CALL_API(value)
rangeEvent.setValue(result_api);
}
}
Keep in mind that this implementation only works when each of the cells is edited one by one. To do the same with a row or a complete array of elements, you must go through each of the cells and follow the same procedure.
I just discovered Google App Scripts, and I'm stumped on something already...
I am trying to write a script for a Google Spreadsheet which finds certain historical stock prices. I found that the FinanceApp service within Google App Scripts has been deprecated, and seemingly replaced by the GOOGLEFINANCE() function within Google Spreadsheets. However, it returns an array, when I need only a single cell, and the array is mucking up the works.
So I'd like to write a short script that calls the GOOGLEFINANCE() spreadsheet function, and finds just the 1 piece of info I need from the array which is returned by GOOGLEFINANCE(). However, I cannot find a way to access Spreadsheet Functions (SUM, VLOOKUP, GOOGLEFINANCE, etc) within a script.
Is there a way to access these functions in a script? Or perhaps, is there a new service which replaces the deprecated FinanceApp service?
Many thanks for any assistance!
You can try this:
var trick = SpreadsheetApp.getActiveSheet().getRange('D2').setValue('=GOOGLEFINANCE("GOOG")').getValue();
Native Spreadsheet functions are not supported in Google Apps Script.
You could eventually use a somewhat cumbersome workaround by reading the value of a cell in which you write a formula (using script in both write and read) but this will be less than practical and / or fast.
You might try the INDEX function combined with GOOGLEFINANCE-
For reference,
=GOOGLEFINANCE("MSFT", "PRICE", "01/01/21")
Returns the array:
Date Close
1/4/2021 217.69
One can add the INDEX function to pick out specific elements from the array using the row,column coordinates of the array.
=INDEX(GOOGLEFINANCE("MSFT", "PRICE", "01/01/21"),2,2)
This returns just the data in row 2, column 2 - 217.69
There is one possible way, with the .setFormula(). This function behave like .setValue() and can be used the following way:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var mySheet = ss.getSheets()[0]
//Code Below selects the first cell in range column A and B
var thisCell = mySheet.getRange('A:B').getCell(1,1);
thisCell.setFormula('=SUM(A2:A4)');
All formulas you write in this function are treated as strings must have ' or " within the .setFormula() input.
I am trying to write a GAS spreadsheet custom function that copies cell content to other cells. And I need to fill the target cells not only with the data of the source cell, but with its formula content (if it has any).
Now, I already know that this is basically impossible through custom functions as they always receive the result of cell calculations but not the cell formulas themselves, and they also cannot return formulas for their target cells.
On the other hand there are functions to read and write cell formulas, e.g. Range.getFormula() and Range.setFormula() which seem to make my endeavor possible. I simply have to find another way of calling them. UPDATE: Meanwhile I found that custom formulas in fact can read formulas using getFormula(), but they definitely don't have permission to write formulas into cells using setFormula().
My question is...
What would be the most elegant method to create something equivalent to a custom function that reads and writes formula content of cells? I think I could use an onEdit function that updates my target cells after each spreadsheet edit, but that would mean that I have to hard code the coordinates of the target cell range, which seems very hacky and would require code changes every time the target range is moved (e.g. when rows are inserted above it).
UPDATE: Example
An example would be a custom function that is able to read multiple ranges of cells (each range given as a distinct function parameter) and returns a joined range of cells.
=rangeJoin(A1:B10;D1:E15)
...would read the two ranges of size 2x10 and 2x15 and would fill a target range of size 2x25 with the subsequent cell contents of both ranges. The target range would start at the cell that contains rangeJoin and would spread 2 cells to the right and 25 cells down (as usual for a custom function). The custom function (or similar mechanism) should be able to copy formulas, so a cell containing =hyperlink("http://www.google.com";"Google") should appear in the target range as a hyperlink and not as a text cell with the naked word 'Google'.
Agree with "Mogsdad"
ie. this custom function works:
function myGrid() {
return [[1,2],[3,"http://www.google.com"]];
}
but, custom functions can't write formulas to a sheet. See https://developers.google.com/apps-script/execution_custom_functions#permissions
As a workaround, you could use a "Trigger", such as a time based trigger, as "Mogsdad" suggests.
I would like to create a Google Apps Script to do the following: When I select a cell containing the name of a person in a spreadsheet (a spreadsheet that records sales, for example), and use a menu button to call the function, the script does a search (a query) using the person's name (or number of his document) in another spreadsheet that stores complete consumer data and that contains all the information that I need from that consumer to generate a contract or a payment receipt.
What is the best strategy to implement this search for information from one spreadsheet in another spreadsheet using Google Apps Script?
Do you have some script sample with a implementation similar to this? THANK YOU in advance for any help/guidance!
There is no event triggered by a cell selection, you'll have to use a menu item or a button to call the function or, if it is acceptable for your use case, edit the cell to trigger an onEdit event.
The 'search part' is actually very simple, the data being on the spreadsheet itself or in another one has no importance, it will simply change the way you access data ( getActiveSpreadsheet or openById()). From there just get all the values and do a search in the resulting 2D array.
EDIT following your comment : here is an example of such a code that returns the range of the found cell (and we get the A1 notation but we could getValue() as well of course.).
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...
}