Populate rows with the sheets names of an spreadsheet - google-apps-script

I have an spreadsheet that contains multiple sheets with some recipes. I'm storing the sheets' titles in the first sheet manually, to reference the recipes titles on another spreadsheet, but this doesn't scale well, so I want to automate the process. I believe I can't do that with any of the built in functions, so I'm trying to build a custom function to do it.
I already know some coding, but my experience with google API is very limited. My current attempt is returning the following exception: "You do not have the permission to call set value". After google this error, I discovered that custom functions seemingly cannot set values to another cells, so I'm here to find an alternative to such a trivial behavior.
This is my current code:
function updateSheetTitles() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var cell = SpreadsheetApp.getActiveSpreadsheet().getCurrentCell();
var row = cell.getRow();
var column = cell.getColumn();
for (var i=0 ; i<sheets.length ; i++){
if(i<1) //For passing trought the first sheet
return;
cell.setValue(sheets[i].getSheetName);
var range = SpreadsheetApp.getActiveSheet().getRange(row+1, column, 1, 1);
cell = SpreadsheetApp.getActiveSheet().setCurrentCell(range);
}
}
And here's and image to illustrate what I want:
This is probably an easy task, but I failed to find a way to build this, so any ideas to accomplish that would be appreciated.

I believe your goal as follows.
You want to retrieve sheet names in the active Google Spreadsheet.
You want to put the sheet names to the active cell.
You want to achieve this using the custom function.
Modification points:
Unfortunately, setValue cannot be used in the custom function. I think that the reason of your issue is due to this.
In your script, at cell.setValue(sheets[i].getSheetName);, the method of getSheetName is not run. If you want to use this method, please add () like getSheetName().
SpreadsheetApp.getActiveSpreadsheet() can be declared one time.
In order to achieve your goal, I would like to propose a custom function for creating an array including the sheet names and returning the array.
When above points are reflected to the sample script, it becomes as follows.
Modified script:
Please copy and paste the following script to the script editor of Google Spreadsheet. And, please put the custom function of =updateSheetTitles() to a cell. By this, the sheet names are returned to the row direction.
function updateSheetTitles() {
return SpreadsheetApp.getActiveSpreadsheet().getSheets().map(e => [e.getSheetName()]);
}
From your replying, when you want to retrieve the sheet names except for 1st and 2nd sheet, you can also use the following script.
function updateSheetTitles() {
return SpreadsheetApp.getActiveSpreadsheet().getSheets().map(e => [e.getSheetName()]).slice(2);
}
References:
Custom Functions in Google Sheets
map()
getSheetName()

Related

Google Sheets, how to run function every x column?

I have a script in google sheets with the following function:
// Function to get current active sheet-name.
function getsheetName(dummy) {
return SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
}
Currently this function runs with this code in sheets:
=getsheetname(3:55)
The reference targets my entire sheet.
So whenever I make a change to a cell in my sheet the function runs again. This causes a huge amount of loading everytime i type anything in a new cell. Can i somehow reference the function to only run when i make changes to every x column instead of every cell?
I tried changing the formula but it would just stop updating completely, tried combining strings and using the MOD operator but I couldn't figure it out (keep in mind i am very new at this so probably missing something in my tinkering).
Appreciate any help!
I believe your goal is as follows.
You want to refresh the custom function of =getsheetname() when the columns "J", "T",,, (every 10 columns).
In this case, how about the following sample script? In order to refresh the function on Google Spreadsheet, I used this method. Ref
Sample script:
In this sample, in order to refresh your custom function, the simple trigger of onEdit is used. Please copy and paste the following script to the script editor of Spreadsheet. And, please save the script. When you use this script, please edit the columns "J", "T" and so on. By this, the script is run.
function onEdit(e) {
if (e.range.columnStart % 10 != 0) return;
const functionName = "=getsheetName";
const temp = "=temp";
const sheet = e.source.getActiveSheet();
sheet.createTextFinder(functionName).matchFormulaText(true).replaceAllWith(temp);
sheet.createTextFinder(temp).matchFormulaText(true).replaceAllWith(functionName);
}
In this case, 3:55 of =getsheetname(3:55) is not required to be used. You can use just =getsheetname().
If you changed the function name of your custom function, please modify const functionName = "=getsheetName";.
Reference:
Simple Triggers

Using Apps Script to return to certain cell and make it editable-ready in Google Sheet

I'm quite new to Apps Script. I hope someone could help me please.
I wanted to create an Apps Script in Google Sheet where the script will return to cell C4 and make it editable-ready. My script is as below:-
function EditC4() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('C4').activate();
}
Problem with this script is that just made C4 active but it is un-editable. Pressing F2 when the C4 is being made 'active' does not work as well. I'm calling the EditC4 function from another function.
I prefer not to use "Browser.msgBox" to make it edit-ready. Could someone please help? I search everywhere but could not find the answer.
Explanation:
The activate() method is used mainly by macros to register some cells or ranges as active and then use getActiveRange() or getActiveCell() to get these ranges back.
In your case, you want to "highlight" or "mark" a particular cell so it can be edited directly with the keyboard.
In this case you want to use activateAsCurrentCell() .
Also it is a better practice to get the range object from the sheet object and not directly from the spreadsheet object.
Solution:
function EditC4() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
sheet.getRange('C4').activateAsCurrentCell();
}
Illustration:

Google Sheets Script to find formulas and copy/paste them into notes

I like to copy/paste as values all of my older sheets to save resources, but I don't want to remove the formulas as I rely on them to re-create them in the future (some are quite complicated). I thought a good alternative would be to copy each formula into its cell's note before I paste as values only, so I thought I could write a script to do this, preferably throughout an entire worksheet. I confess I'm googling as I go here, but am I on the right track? Do I have the right variables to start working on the loop?
function CopyFormulaToNote() {
/* I dont' want to get just the active sheet but all of them
look into how to do that */
var ss=SpreadsheetApp.getActive().getActiveSheet();
var lr=ss.getLastRow();
var lc=ss.getLastColumn();
var range=ss.getRange(1,1,lr,lc);
/* Find the first formula in the entire spreadsheet
I doubt it will just find all formulas per se without specifying that a formula begins with =
although there is a getFormula function...
and if I do have to specify that I think what I have below says to look for = as the first character */
var search=range.createTextFinder().matchFormulaText("^[=]"); //search for formula ie first character =
var result=search.getCurrentMatch(); //I *think* this would get the 1st result
var cell=result.getCell(row, column); //get the cell range of the result
var note=cell.setNote(note); //create a cell note for that cell
/* and now create a loop to do it everywhere that includes */
result.CopyTo(note); //copy the result into the note
}
You want to retrieve the formulas from all cells in all sheets in the Google Spreadsheet.
You want to put the retrieved formulas to each cell as the note.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
I thought that in your case, the script can be simpler by getFormulas() and setNotes().
Sample script:
function myFunction() {
SpreadsheetApp
.getActiveSpreadsheet()
.getSheets()
.forEach(function(sheet) {
var range = sheet.getDataRange();
range.setNotes(range.getFormulas());
});
}
References:
forEach()
getFormulas()
setNotes(notes)
If I misunderstood your question and this was not the direction you want, I apologize.

Get row number from a Google Visualization API query to a Google Sheet

I have a query to a google sheet that is working as I expect. I'm using Postman to do my testing because in my app — which is a desktop app, I cannot use any of the SDKs that Google provides. This is not a web app, so I cannot use even Javascript source that is hosted on Google's CDN. In any case, I'm querying a spreadsheet that has many rows, with a particular column that I'm querying for:
I'm using the following endpoint, after having retrieved an authentication token via OAuth2 methodology:
https://docs.google.com/a/google.com/spreadsheets/d/{{sheet_key}}/gviz/tq?sheet={{tab_name}}&tq={{sheet_query}}
The {{sheet_query}} variable in Postman, which handles the URL encoding properly is set to the following:
select * where C = 'ready'
The response for my particular worksheet is what I would expect and the data is correct. There are three rows in the sheet where column C is set to 'ready' which is great.
Now, the response to this GET request does not appear to send back the ordinal row index for the retrieved rows, it just send the rows' data. The problem is that I want to write back to these rows via the Google Sheets API v4 which now uses the A1 notation as a method to target which cell range to update.
The problem is that in order to write back to these rows retrieved via my Visualization API request, I would need the rows' ordinal indices for the requests to the Google Sheets API. Is there any way to get each row's ordinal index from the Sheet in the request to the Visualization API call?
I found this Stack Overflow thread, but I'm not exactly sure if this can work in my case as I'm essentially building the requests manually and without an SDK. I'm also not using Google Apps Script, I'm using the Visualization API. The only workaround I can think of is to force the end-user to ensure the worksheet to be queried has a column whose cells have the =ROW() formula, but I would rather not make that a requirement on the user's part.
Any insights or guidance is appreciated.
You want to retrieve the row numbers by searching a value from the sheet in Google Spreadsheet.
You want to achieve this using Google Apps Script.
I could understand like above. If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Flow:
Retrieve the sheet object.
Search values in a sheet using a search value.
In this case, I used TextFinder.
Retrieve the row numbers from the searched result.
Sample script:
Please copy and paste the following sample script to the script editor, and set the variables of searchValue, spreadsheetId, sheetName. Then, as a test run, please run the function of testRun(). By this, the row numbers are returned as an array.
function getRowNumberBySearch(searchValue, spreadsheetId, sheetName) {
var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
var t = sheet.createTextFinder(searchValue).findAll();
return t.map(function(e) {return e.getRow()});
}
// Please run this function.
function testRun() {
var searchValue = "sample";
var spreadsheetId = "###";
var sheetName = "Sheet1";
var res = getRowNumberBySearch(searchValue, spreadsheetId, sheetName);
Logger.log(res)
}
References:
Class TextFinder
map()
Added:
Additional question 1:
is there a way to narrow the .findAll() method to a specific range within the sheet so that it focuses on a single column?
Sample script:
function getRowNumberBySearch(searchValue, spreadsheetId, sheetName, range) {
var range = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName).getRange(range);
var t = range.createTextFinder(searchValue).findAll();
return t.map(function(e) {return e.getRow()});
}
In this case, range is a1Notation.
Additional question 2:
is it possible to return all of the values of the row and not just their index?
Sample script:
function getRowNumberBySearch(searchValue, spreadsheetId, sheetName, range) {
var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
var t = sheet.getRange(range).createTextFinder(searchValue).findAll();
return t.map(function(e) {return sheet.getRange(e.getRow(), 1, 1, sheet.getLastColumn()).getValues()[0]});
}
In this case, range is a1Notation.
I think that in this case, the endpoint of your question can be also used.

Is it possible to do ImportRange in Google Apps Script?

I have been playing around with Google Apps Script today and I am trying to code some custom spreadsheet functions. I have done some searching but cannot find an answer to my query.
I know that on a Google Spreadsheet you can use ImportRange in a cell on a spreadsheet like this:
=ImportRange(spreadsheet_key;sheet!range_of_cells)
My questions are is it possible to do something similar in a Google Apps Script and if so, how?
I want to import a range of cells from a sheet on another spreadsheet (not a sheet on the spreadsheet where the script will reside).
Yes, this is perfectly possible. You just need to call SpreadsheetApp.openById and then get the desired sheet and ranges normally.
Please take a look at the documentation : range.getValues() and range.setValues() are very basic GAS methods and are pretty well described.
Read the tutorial as well.
It seems Google, in their infinite wisdom, has altered the behavior of openById and similar functions. They are no longer allowed in the context of custom functions.
See https://code.google.com/p/google-apps-script-issues/issues/detail?id=5174 for more details.
They suggest using IMPORTRANGE as a workaround, but as previously mentioned, this needs to be called within a cell.
Our solution was to use IMPORTRANGE in the sheet, and pass the acquired data into our custom function, as the data set was small. I hope this information helps!
I needed to do this recently. This is what I came up with, simply hard-coding the spreadsheet key and range into ahab's myImportRange function
// to be used in the spreadsheet like so: = myScriptedImportRange( GoogleClock() )
// no need to include key or range because they are in the script here
//
// the third parameter - GoogleClock() - triggers an automatic update every minute.
// updated 2011-07-17 (ahab): better regex to strip sheetname of *outer* single quotes
// updated 2013-01-27 (ben) to hard-code key and range
function myScriptedImportRange( ) {
var key = "PUT YOUR DATA_SPREADSHEET_ID IN HERE"
var sheetrange = "PUT YOUR SHEET AND CELL RANGE IN HERE"
var shra = sheetrange.split("!") ;
if (shra.length==1) shra[1]=shra[0], shra[0]="";
var sheetstring = shra[0].replace( /^'(.*)'$/g , "$1") // was: replace( /'/g , "") ; updated 2011-07-17 (ahab)
var rangestring = shra[1]
var source = SpreadsheetApp.openById( key )
if ( sheetstring.length==0 ) sheet = source.getSheets()[0] ;
else sheet = source.getSheetByName( sheetstring ) ;
return sheet.getRange( rangestring ).getValues();
}
In my case I have a set of private sheets, an intermediate sheet that uses the regular myImportRange and VMERGE with some SQL to combine selections from the private sheets into the intermediate sheet, and then a public sheet that simply has one cell containing = myScriptedImportRange( GoogleClock() )
Note that there is a similar approach here: https://stackoverflow.com/a/11857014
Note also that the ImportRange function and related functions often have a problem of not displaying the imported data when the origin workbook(s) is/are not open. A simple way around this has been described in a comment here: https://stackoverflow.com/a/11786797