Linked List of Sheets - google-apps-script

I have two functions I'm looking to join together and I'm struggling with it. The first function lists all of the tabs I have in the sheet (on the actual doc I'm working on this is just over 100 tabs and growing).
function listsheets() {
var out = new Array()
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var i=0 ; i<sheets.length ; i++) out.push( [ sheets[i].getName() ] )
return out
}
The second function links cells based on there text; i.e., if there is a "data" cell, it would link to the "data" tab in my workbook.
function linkRange() {
const startRow = 2,
column = 1;
const spreadsheet = SpreadsheetApp.getActive(),
sheet = spreadsheet.getSheetByName("List of Sheets"),
lastRow = sheet.getLastRow();
for (let row = startRow; row <= lastRow; row++) {
const range = sheet.getRange(row, column),
richTextValue = range.getRichTextValue(),
targetSheet = spreadsheet.getSheetByName(richTextValue.getText());
if (targetSheet !== null) {
const sheetId = targetSheet.getSheetId(),
builder = richTextValue.copy().setLinkUrl(`#gid=${sheetId}`);
range.setRichTextValue(builder.build());
}
}
}
What I am ultimately looking for is a way to automatically link this list of sheets, so the custom function would essentially read as "linkRange(listsheets())".

Sorry if misunderstood your goal. From your code I suspect you need this:
function build_list_of_sheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var list = [];
for (var sheet of sheets) {
var value = SpreadsheetApp.newRichTextValue()
.setText(sheet.getName())
.setLinkUrl('#gid=' + sheet.getSheetId())
.build();
list.push([value]);
}
var sh = ss.getSheetByName('List of Sheets');
sh.getRange(2,1,list.length,1).setRichTextValues(list);
}
It takes the names all sheets and put them into column A of the sheet 'List of Sheets' as a list of links:

Related

Google Sheets - Two-way lookup pulling data from multiple sheet tabs

I've been working on a sheet where I want to have and input tab and output tab.
The input tab is basically a table and the output tab will be a calendar (of sorts).
In my example:
Sheet1 = input tab
Sheet2 = output tab
I wish to have a vlookup that will pull its search_key from Sheet2 (output) and search it against a range in Sheet1.
I've been messing around with the following (green cell Sheet2 in example):
=IFERROR(VLOOKUP(A2,Sheet1!$A$2:$C$7,MATCH(B1,Sheet1!$A$2:$C$7,0),False))
I had also tried a variation of this using hlookup instead of MATCH but didn't have much luck with it.
The problem I have is that I no longer know where to place my column index. In my example sheet I have it working with a one way vlookup (blue cell Sheet2) that returns the desired value from Sheet1 (Length Column) using this index. Is it not possible to do so in the two way lookup??
Here's a link to the example:
https://docs.google.com/spreadsheets/d/1_nqH-XOxNhQAUVJzesNBZeMci7AV9RowSQUnptAruPc/edit?usp=sharing
Try running this function in Apps Script:
function myFunction() {
var ss = SpreadsheetApp.getActive();
var sheet1 = ss.getSheetByName('Sheet1');
var sheet2 = ss.getSheetByName('Sheet2');
var firstRow = 2;
var numRows = sheet1.getLastRow() - 1;
var firstCol = 1;
var numCols = sheet1.getLastColumn();
var inputData = sheet1.getRange(firstRow, firstCol, numRows, numCols).getValues();
var numBrands = sheet2.getLastRow();
var outputRange = sheet2.getDataRange();
var outputData = outputRange.getValues();
// Iterating through each row in Sheet1 data:
for(var i = 0; i < numRows; i++) {
// Iterating through each row in Sheet2:
for(var j = 1; j < outputData.length; j++) {
// Iterates through each cell for each row in Sheet2.
for(var k = 1; k < outputData[0].length; k++) {
var inputBrand = inputData[i][0];
var outputBrand = outputData[j][0];
var inputDate = inputData[i][1];
var outputDate = outputData[0][k];
// It checks whether the date and brand corresponding to each cell
// (same row or column) matches the date and brand in the current
// row in Sheet1
if(inputBrand == outputBrand && inputDate.toString() == outputDate.toString()) {
var inputLength = inputData[i][2];
sheet2.getRange(j+1, k+1, 1, 1).setValue(inputLength);
}
}
}
}
}

Is it possible to export (using Google Scripts) a single sheet to PDF without hiding sheets?

I would like to be able to export a single specific sheet from a large workbook without having to hide the unrequired sheets. Is that actually possible with Google Scripts?
At the moment I am looping through a list of products, updating a query for each one and then exporting each result to an individual PDF. Basically creating a product "Printout" page for many products.
The code below works quite nicely but it starts by hiding all sheets other than my Printout page. That would be fine except some of the other sheets are protected and not all users that would be using my export functionality have the right to hide sheets.
I've considered adding an unprotect/protect function to my macro but it would be good to know if exporting a single sheet was an option before i went down this route?
The hiding sheets trick was from this post Export Single Sheet to PDF in Apps Script
function exportLoopedSheet(firstRow, lastRow) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = 'Printout'; // update for print sheet name
var productSheetName = 'ProductList'; // update for final product list
var folderName = 'productPDFs';
var main = ss.getSheetByName(sheetName);
var sheets = ss.getSheets();
var productList = ss.getSheetByName(productSheetName);
var lastProductRow = lastRow;
var firstProductRow = firstRow;
// Hide all sheets other than the Print Sheet
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() !== sheetName) {
sheets[i].hideSheet();
}
}
for (var prodNo = firstProductRow; prodNo < lastProductRow + 1; prodNo ++) {
var currentProduct = productList.getRange('A'+ prodNo).getValue();
main.getRange('B9').setValue(currentProduct);
// Ensure all changes are updated
SpreadsheetApp.flush();
// call the export sheet function
exportSheet();
}
// Unhide the sheets
for (i = 0; i < sheets.length; i++) {
sheets[i].showSheet();
}
}
function exportSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = 'Printout';
var main = ss.getSheetByName(sheetName);
var sheets = ss.getSheets();
//Hide All Empty Rows in the Print Sheet
var maxRows = main.getMaxRows();
var lastRow = main.getLastRow();
if (maxRows-lastRow != 0){
main.hideRows(lastRow+1, maxRows-lastRow);
}
// Save pdf version
var folder = 'productPDF';
var parentFolder = DriveApp.getFolderById('1234'); //add this line...
var folder, folders = DriveApp.getFoldersByName(folder);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = parentFolder.createFolder(folder);
}
var name = main.getRange("B8").getValue();
folder.createFile(ss.getBlob().setName(name));
// Unhide the rows again
var fullSheetRange = main.getRange(1,1,main.getMaxRows(), main.getMaxColumns());
main.unhideRow(fullSheetRange);
}

Google Scripts - Copy rows to a new sheet when column H has a specific colour (Yellow)

I've played around with this script but have still yet to get it to work.
I need a script that looks at the column F's background color in the sheet called Test.
If the cell background in Column F is yellow it will copy that entire row to a new sheet called New Data.
Please find attached the Google Spreadsheet link: https://docs.google.com/spreadsheets/d/19pMAmB94tOoV14MiSPyoPhty2dO5OudO4NupP8KhJA4/edit#gid=1703438513
Any help would be greatly appreciated!
function Extract(){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Test');
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getBackgrounds();
var yellowColour = '#ffff00';
var whiteColour = '#ffffff';
var newSheet = ss.getSheetByName('New Sheet');
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
if (row[6] === whiteColour ) {
}
else {
newSheet.appendRow(row);
}
} // End of For Loop
};
Try this. It creates an array of rows where F is yellow. It clears the old data in 'New Data' and copies in the new array:
function Extract(){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Test');
var lr=sheet.getLastRow()
var data = sheet.getRange(2,1,lr,15).getValues();//get Test values
var rows = sheet.getRange(2,6,lr,1).getBackgrounds();//get F background colors
var yellowColour = '#ffff00';
var newSheet = ss.getSheetByName('New Data');
var lr1= newSheet.getLastRow()
var newData=[] //new array
for (var i = 0; i <= lr - 1; i++) {
if (rows[i] == yellowColour ) { //if F = yellow
newData.push(data[i]) // add to new array
}}
newSheet.getRange(2,1,lr1+1,15).clearContent()//clear old content excluding header row
newSheet.getRange(2,1,newData.length,15).setValues(newData)//set new comtent
};

Google Sheets: getting a sheet by its index

I am trying to get a sheet using a calculated index. I am having a problem but am unsure whether it's a problem converting a float to an integer or if there is a syntax error. What am I getting wrong?
function copySheetValues()
{
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = SpreadsheetApp.getActiveSheet();
//get the source sheet data
var sourceDataRange = sourceSheet.getDataRange();
var sourceSheetValues = sourceDataRange.getValues();
var sourceRows = sourceDataRange.getNumRows();
var sourceColumns = sourceDataRange.getNumColumns();
// get the source sheet index and set the next sheet index
var sourcesheetIndex = sourceSheet.getIndex();
var destinationsheetIndex = Math.round(sourcesheetIndex + 1);
// get the next sheet
var destinationSheet = spread.getSheets()[destinationsheetIndex]
//destination.insertSheet(sourcename, 0);
destinationSheet.getDataRange().offset(0, 0, sourceRows, sourceColumns).setValues(sourceSheetValues);
}
As getIndex() is 1 based and getSheets() is 0 based you might try:
var destinationSheet = spread.getSheets()[sourceSheet.getIndex()];
go figure
Caveat: getIndex() returns the sheets position within the spreadsheet where getSheets() has to do with the order in which the sheets were added and the two may not correspond if the spreadsheet has been rearranged after the sheets were added.
To insure that the destination sheet is the sheet located just after the source sheet:
// get the source sheet index and set the next sheet index
var destinationsheetIndex = sourceSheet.getIndex() + 1;
// get the next sheet
var sheets = spread.getSheets();
for (var i=0; i<sheets.length; i++) {
if(sheets[i].getIndex() == destinationsheetIndex ) {
var destinationSheet = sheets[i];
break;
};
};

Google Spreadsheet, Checking the name of the sheet with a cell in a sheet

I have a Google spreadsheet with 3 sheets.
In the first sheet I have a resume of the two other sheet. This sheet has a column "C" where the name of the sheet corresponding to the resume is written.
Now I want a script that checks the name of the sheets and color the corresponding cell in column "C" into red if the name matches with the one in column "C".
I have written this code but doesn't seem to be working!
function myFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var ss = SpreadsheetApp.getActiveSpreadsheet();
var columnC = sheet.getRange (1, 3, sheet.getLastRow(), 1);
var Cvalues = columnC.getValues();
var allSheets = ss.getSheets();
var allSheetNames = new Array();
for (var i = 0; i < allSheets.length; i++)
{
allSheetNames.push(allSheets[i].getName());
}
for (var j=0 ; j < Cvalues.length; j++)
{
if (Cvalues[j][0] == allSheets) {
sheet.getRange( j, 1, 1, 1).setBackgroundColor('red');}
}
}
Problem here:
if (Cvalues[j][0] == allSheets) {
Your allSheets is an array, so the value in Cvalues[j][0] can never be equal to it. What you probably want it to determine if Cvalues[j][0] appears anywhere in allSheets. Here's how you'd do that:
if (allSheets.indexOf(Cvalues[j][0]) !== -1) {
...