if I have a workbook with 20 or so sheets, is there a way I can easily save each one as their own workbook? Is this possible with scripts?
This can be done with a script as follows: (a) get the list of sheets; (b) for each, create a new spreadsheet, naming it after the sheet; (c) copy the sheet there; (d) delete the initial "Sheet1" sheet from the new spreadsheet, so that it doesn't get in the way.
function saveEach() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (var i = 0; i < sheets.length; i++) {
var newss = SpreadsheetApp.create(sheets[i].getSheetName());
sheets[i].copyTo(newss);
newss.deleteSheet(newss.getSheets()[0]);
}
}
Reference: SpreadsheetApp
Related
I found code to list the names of all the sheets in Google Sheets
function sheetnames() {
var out = new Array()
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets()
for (var i=2 ; i<sheets.length ; i++) out.push( [ sheets[i].getName() ] )
return out
}
But we must place =sheetnames() in a cell to get value.
Is there any improvement in the script to automatically update when creating a new sheet?
You have to install an onChange trigger, which runs a function whenever a user modifies the structure of the spreadsheet—for example, when a sheet is inserted or removed.
You can install the trigger manually, following these steps, or programmatically, executing this function once:
function createOnChangeTrigger() {
const ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("writeSheetNames")
.forSpreadsheet(ss)
.onChange()
.create();
}
Once this is installed, the function writeSheetNames will run every time a sheet is created, removed, or renamed. This function should do two things:
Retrieve the sheet names of all the sheets in the spreadsheet.
Write these sheet names to the cell you indicate.
For example, the function below would write the data to column A of the sheet named Sheet1.
Code sample:
function writeSheetNames() {
const ss = SpreadsheetApp.getActive();
const sheetNames = ss.getSheets().map(sheet => [sheet.getName()]);
const sheet = ss.getSheetByName("Sheet1");
sheet.getRange("A:A").clear(); // Delete previous data
sheet.getRange(1,1,sheetNames.length).setValues(sheetNames);
}
Reference:
onChange
I am trying to count visible columns in a spreadsheet with no luck. I've been trying using SUBTOTAL function but it's applied to hidden/visible rows only. I also tried working with CELL("width") function, but it doesn't return 0 when a cell is hidden
Is there any other option to ignore hidden columns in a count formula?
You can definitely create your own custom function using Google Apps Script.
For example, the following function counts the number of visible columns in your active sheet:
function countVisibleColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet()
var n_cols = sheet.getMaxColumns();
var hidden_cols = []
var cnt = 0;
for (var i=1; i<=n_cols ; i++) {
if ( sheet.isColumnHiddenByUser(i) ){
continue;}
else {cnt +=1} }
Logger.log(cnt)
return cnt;
}
You just need to click on Tools => Script editor and then copy the aforementioned code into a blank script. Then you can directly use the function as a formula in the google sheet like =countVisibleColumns().
See screenshot attached for more information.
I am trying to write a formula that counts the number of times the number 1 appears in cell F1 of all my sheets. My sheets have varying names (18-0100, 18-0101, 18-0102...). I tried the following formula:
=COUNTIF(INDIRECT("'"&"'!F1"),"=1")
It acts unpredictably. It will only return 1 even if it should be more than 1. And when I try to start trying to count 2 instead of 1 it returns 0 and not the correct number.
What am I doing wrong?
Your formula counts only the current sheet.
To get them all you need to enter all sheet names:
The formula for each sheet is:
=(INDIRECT("'"& sheet_name &"'!F1")=1)*1
You can leverage a Google Apps Script to pull this off as well.
From your spreadsheet, go to Tools > Script Editor. Add the code below, then save. The function saved there will be accessible by all other Google apps, including your spreadsheet. You can then use the name of the function in your spreadsheet like you would with any other formula.
function OccurrencesInSheetNames(str) {
var c = 0;
var regExp = new RegExp('[' + str + ']', 'g');
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var sheetnames = [];
for (var i=0; i<sheets.length; i++) {
sheetnames.push([sheets[i].getName()]);
}
for (var i=0; i<sheetnames.length; i++) {
var name = sheetnames[i].toString();
var count = (name.match(regExp) || []).length;
c += count;
}
return c;
}
Now in your cell F1, place the following formula:
=OccurrencesInSheetNames(TEXT(1,0))
You can also replace the 1 in the above formula with a cell reference, if that works better for your needs. (e.g. =OccurrencesInSheetNames(TEXT(C5,0)) if you want to search through your sheet names for the integer number found in cell C5.)
Here's a demo spreadsheet for you to try out.
I made some 'conditional formatting' in Google Sheets for one sheet but I need to apply to others. There are about 45 tables and I really don't want to copy-paste it. Can anyone help me with that?
A quick solution would be to do the following:
Record a macro of how you apply the conditional formatting on the first sheet
Edit the macro so that it loops through each sheet (see code example below)
Be sure to do this on a copy of the original sheet first in case there are any issues
Code:
function autoConditionalFormat() {
// Counts how many sheets there are
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
numSheets = sheets.length;
// Loop to get name of each tab (sheet)
var tabNames = new Array()
for (var i=0; i<numSheets; i++) tabNames.push( [ sheets[i].getName() ] )
// Loops through each sheet
for (var i = 0; i < numSheets; i++) {
// Applies some conditional formatting to each sheet
SpreadsheetApp.setActiveSheet(ss.getSheetByName(tabNames[i]));
// Insert what your macro recorded here:
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A2').activate();
var conditionalFormatRules = spreadsheet.getActiveSheet().getConditionalFormatRules();
conditionalFormatRules.push(SpreadsheetApp
.newConditionalFormatRule()
.setRanges([spreadsheet.getRange('A2')])
.whenCellNotEmpty()
.setBackground('#B7E1CD')
.build());
spreadsheet.getActiveSheet()
.setConditionalFormatRules(conditionalFormatRules);
}
}
}
Project description: Begin with a roster spreadsheet with multiple tabs (one for each group), each tab with a list of members for rows. Columns are rehearsal or program dates. Second sheet contains scanned attendance records. Open the attendance record sheet and read each record. One column contains tab name of sheet on the roster sheet. Change to that sheet and search for the scanned member. Mark the column matching the date with an X to denote attendance. Mark the scanned attendance record with an X to denote processed.
Everything is working save the final writing of the X to the sheet opened by ID. I can't figure out the syntax to update the appropriate row/col cell.
I'd appreciate some help. Thanks!
function processAttendanceRecords(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var ss = SpreadsheetApp.openById("1234567");
var data = ss.getDataRange().getValues();
for (var i = 1; i < data.length; i++) {
var rhrsDate = Utilities.formatDate(data[i][3], "PST", "M/d");
sheet.setActiveSheet(sheet.getSheetByName(data[i][1]));
var members = sheet.getDataRange().getValues();
var col = members[0].indexOf(rhrsDate);
for (var j = 1; j < members.length; j++) {
if (data[i][6] == members[j][0] && data[i][7] == members[j][1]) {
SpreadsheetApp.getActiveSheet().getRange(j+1,col+1).setValue('X');
SpreadsheetApp.getActiveSheet(ss).getRange(i+1,9).setValue('X');
}
}
}
}
If you are accessing spreadsheet by ID then it is good practice to mention the sheet name or else it will take the first sheet by default.
var ss = SpreadsheetApp.openById("123456").getSheetByName("Sheet1");
Since you haven't defined the sheet name you can't use getRange(Row, Column). So your need to mention the sheet name like above and then change the last line.
ss.getRange(i+1,9).setValue('X');