I'm trying to create a dynamic HYPERLINK formula that will automatically create the link based on the sheet name in Column A, but I'm not sure how (or if it's possible) to get the URL of the sheet based on the name.
Here's the setup:
Single Google Spreadsheet with multiple tabs
Tab names: 1500, 1501, 1502, Consolidated
On the Consolidated tab, I have two columns: Column A is the Sheet Name, and Column B is a HYPERLINK formula, that when clicked should open the corresponding sheet.
Is there a way to programmatically get the URL for the sheet based on the sheet name in Column A? Perhaps I could use a script to populate Column C with the URL, then use the following formula: =HYPERLINK(C2,A2)?
Thanks for the help!
Surprised to see this as a top search on Google but with no answer.
Anyway, here's the method I found that works for me: combine Hyperlink with values from a different column using the &, a basic example is shown below:
If you are trying to automatically generate direct URL's to specific sheets based on their name, and do not want to use scripts, you are out of luck. Currently, the only way to link directly to specific sheets is by appending the correct gid number to the spreadsheet URL. A gid must be either copied manually from the active sheet's URL, or automatically extracted with a custom function, created using scripts.
Since you're open to using scripts, it looks like i found a detailed tutorial of how to do this. https://www.benlcollins.com/spreadsheets/index-sheet/
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Index Menu')
.addItem('Create Index', 'createIndex')
.addItem('Update Index', 'updateIndex')
.addToUi();
}
// function to create the index
function createIndex() {
// Get all the different sheet IDs
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var namesArray = sheetNamesIds(sheets);
var indexSheetNames = namesArray[0];
var indexSheetIds = namesArray[1];
// check if sheet called sheet called already exists
// if no index sheet exists, create one
if (ss.getSheetByName('index') == null) {
var indexSheet = ss.insertSheet('Index',0);
}
// if sheet called index does exist, prompt user for a different name or option to
cancel
else {
var indexNewName = Browser.inputBox('The name Index is already being used,
please choose a different name:', 'Please choose another name',
Browser.Buttons.OK_CANCEL);
if (indexNewName != 'cancel') {
var indexSheet = ss.insertSheet(indexNewName,0);
}
else {
Browser.msgBox('No index sheet created');
}
}
// add sheet title, sheet names and hyperlink formulas
if (indexSheet) {
printIndex(indexSheet,indexSheetNames,indexSheetIds);
}
}
// function to update the index, assumes index is the first sheet in the workbook
function updateIndex() {
// Get all the different sheet IDs
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var indexSheet = sheets[0];
var namesArray = sheetNamesIds(sheets);
var indexSheetNames = namesArray[0];
var indexSheetIds = namesArray[1];
printIndex(indexSheet,indexSheetNames,indexSheetIds);
}
// function to print out the index
function printIndex(sheet,names,formulas) {
sheet.clearContents();
sheet.getRange(1,1).setValue('Workbook Index').setFontWeight('bold');
sheet.getRange(3,1,names.length,1).setValues(names);
sheet.getRange(3,2,formulas.length,1).setFormulas(formulas);
}
// function to create array of sheet names and sheet ids
function sheetNamesIds(sheets) {
var indexSheetNames = [];
var indexSheetIds = [];
// create array of sheet names and sheet gids
sheets.forEach(function(sheet){
indexSheetNames.push([sheet.getSheetName()]);
indexSheetIds.push(['=hyperlink("#gid='
+ sheet.getSheetId()
+ '","'
+ sheet.getSheetName()
+ '")']);
});
return [indexSheetNames, indexSheetIds];
}
Related
I currently use a Google sheet to hold data x1 row per item. I use one particular cell to hold two separate hyperlinks within (x2 website addresses), both links are relevant/in relation to this item.
I want to keep the structure of having two separate clickable hyperlinks in one cell, but I also need to import this cell data (these two links) into another Google sheet, is there a way of using IMPORTRANGE and retaining these two separate hyperlinks (ensuring clickable & still x2 separate links within one cell), or converting them into hyperlinks when importing into another sheet?
Thank you in advance
I've created two dummy sheets with data for testing & to help visualise
Sheet Name: "Static" & Sheet URL: https://docs.google.com/spreadsheets/d/1JS40eNGUAmBqQJqmdX4PhWtm6GEVQP64CoxO_DooZYM/edit#gid=0
Sheet Name: "Imported" & Sheet URL: https://docs.google.com/spreadsheets/d/1rhnULIcbkSMCp8AONa7UwTQz77uHn443VuwYjty2xFs/edit#gid=0
I've used =IMPORTRANGE("1JS40eNGUAmBqQJqmdX4PhWtm6GEVQP64CoxO_DooZYM","Static1!A1:D")
To pull data from 'Static' sheet (tab: 'Static1') into 'Imported' (tab: 'Imported1')
I'm hoping to get clickable links in column 'D' of the 'Imported' sheet
I've added different variations i.e. the hyperlinks are renamed in 'Static' sheet as "Link 1" & "Link 2", I've added a few rows with full URLs addresses (no re-naming), and a couple with full URLs and with an empty line in between - I'm not too fussed with how they look to be honest (ideally it would be nice to have 'Link 1' & 'Link 2') but mainly just looking to have x2 imported URLs within same cell that remain/become clickable after importing
This is because I'll also be iframe/embedding the 'Imported' sheet afterwards.
Thank you
You can extract the urls by a custom function in addition of the IMPORTRANGE
function extractUrls(range) {
var activeRg = SpreadsheetApp.getActiveRange();
var activeSht = SpreadsheetApp.getActiveSheet();
var activeformula = activeRg.getFormula();
var rngAddress = activeformula.match(/\((.*)\)/).pop().trim();
var urls = activeSht
.getRange(rngAddress)
.getRichTextValue()
.getRuns()
.reduce((array, e) => {
var url = e.getLinkUrl();
if (url) array.push(url);
return array;
}, []);
return ([urls])
}
edit
in your situation
function createCopy() {
var id = "1JS40eNGUAmBqQJqmdX4PhWtm6GEVQP64CoxO_DooZYM"
var source = SpreadsheetApp.openById(id).getSheets()[0]
var values = source.getRange(2,1,source.getLastRow()-1,3).getValues()
var richTxt = source.getRange(2,4,source.getLastRow()-1,1).getRichTextValues()
var output = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('output_v2')
output.getRange(2, 1, values.length, values[0].length).setValues(values)
output.getRange(2, 4, richTxt.length, richTxt[0].length).setRichTextValues(richTxt)
}
UPDATE:
Option 1:
This is fairly straightforward. It just copies the Static1 sheet unto a destination sheet and names it Imported.
function createCopy2() {
var ss = SpreadsheetApp.openById("1vM-0nBBlhVvRQ3vvXwkWlecENM7CVuv8iei3cl0uRQI");
var ds = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Static1');
sheet.copyTo(ds).setName('Imported');
}
Option 2 (incomplete):
This is what I have done so far, but this still throws an error Exception: Illegal Argument at this line var text = SpreadsheetApp.newRichTextValue().setText(linkval[i]).setLinkUrl(0,7,urls1[i]).setLinkUrl(7,13,urls2[i]).build();.
(P.S: Just wanted to throw this out here if in case someone would find this logic useful/not to waste my efforts practicing JS lol).
Kudos to Mike Steelson for providing a working answer.
function createCopy() {
//Creates a full copy of the source sheet without Hyperlinks (AKA importrange in script form)
var ss = SpreadsheetApp.openById("1vM-0nBBlhVvRQ3vvXwkWlecENM7CVuv8iei3cl0uRQI");
var sheet = ss.getSheets()[0].getSheetValues(1,1, ss.getLastRow(), ss.getLastColumn());
var ds = SpreadsheetApp.getActiveSheet();
ds.getRange(1,1, ss.getLastRow(), ss.getLastColumn()).setValues(sheet);
Logger.log(sheet);
var link = ds.getRange(2,4, ss.getLastRow(), 1);
var linkval = link.getValues();
var urls1 = ds.getRange(2,5, ss.getLastRow(), 1).getValues();
var urls2 = ds.getRange(2,6, ss.getLastRow(), 1).getValues();
for(i=0; i < ss.getLastRow(); i++){
var text = SpreadsheetApp.newRichTextValue().setText(linkval[i]).setLinkUrl(0,7,urls1[i]).setLinkUrl(7,13,urls2[i]).build();
}
}
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.
need some help with script on google sheets
I'm having some issues to try to use "setVisibleValues" and I got an error saying "Exception: Visible values are not currently supported. As an alternative specify a list of hidden values that excludes the values that should be visible.". But my problem is, I've a huge number of employee names on a list, and I wanna filter just based in one person.
I cant show some information, but the thing is: "I just wanna filter one value, and I don't know how to do it using "setHiddenValues".
function Filtersheet() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A3:S').activate();
spreadsheet.getRange('H3').activate();
var criteria = SpreadsheetApp.newFilterCriteria()
.setHiddenValues([''])
var criteria = SpreadsheetApp.newFilterCriteria()
.setVisibleValues(['tayzer'])
.build();
spreadsheet.getActiveSheet().getFilter().setColumnFilterCriteria(8, criteria);
}
Lets say that the names of the Employees are : jorge, lucas, nuno, fernando, marta, beatriz, tayzer, larissa, and I wanna use the filter script to only show on the column the information related to tayzer
But my way to change the filter employee will be on a cell outside the script (cause I've around 200 employees)
Thanks in advance for the help
try this
function setFilter() {
// replace 'sheet name' with you sheet
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet name');
var range = ss.getDataRange();
var filter = range.getFilter() || range.createFilter()
var criteria = SpreadsheetApp.newFilterCriteria().whenTextContains('tayzer');
filter.setColumnFilterCriteria(8, criteria);
}
if i am not wrong if you put "jorge" in cell_C4 you want it to filter "jorge" in column E, if so try below code.
function setFilter() {
// replace 'sheet name' with you sheet
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet name');
var range = ss.getDataRange();
var filter = range.getFilter() || range.createFilter()
var criteria = SpreadsheetApp.newFilterCriteria().whenTextContains(ss.getRange('C4').getValue()).build();
filter.setColumnFilterCriteria(8,criteria)
}
I have a google sheet that I would like to have generate an email alert when one column is greater than the other. Specifically, column F > column G. Here is what I have so far, any advice would be greatly appreciated, as I do not have much skill writing functions.
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Watch list");
var value = sheet.getRange("F2").getValue();
var value1 = sheet.getRange("G2").getValue();
if(value>value1) MailApp.sendEmail('example#gmail.com', 'subject', 'message');
};
Currently this only attempts to compare cell F2 to cell G2. Is there a way to make the function compare the entire F column against column G, and generate an email for each individual case where Fx > Gx ?
Thank you!!
You have to loop all over the range.
first instead of getting the content of one cell you'll need to get the content of all the column:
var value = sheet.getRange("F2").getValue();
become that
var values = sheet.getRange("F2:F").getValues();
(same for value1)
then you need to create an empty table that will collect the results:
var results = [];
and now you need to loop throught all the values:
for(var i=0;i<values.length;i++){
//do the comparaison and store result if greater for example
}
then you may send the result.
all put together it give something like that:
function readCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Watch list");
var values = sheet.getRange("F2:F").getValues();
var value1s = sheet.getRange("G2:G").getValues();
var results = [];
for(var i=0;i<values.length;i++){
if(values[i]<value1s[i]){
results.push("alert on line: "+(i+2)); // +2 because the loop start at zero and first line is the second one (F2)
}
}
MailApp.sendEmail('example#gmail.com', 'subject', results.join("\n"));
};
If you want to trigger that function automatically you'll also need to change the way you call the spreadsheet (instead of getActive.... you'll need to use openById)
I have a lot of named ranges in my spreadsheet and time to time I need to delete all of them and create new one. In past I did this by deleting worksheet but recently I've discovered that this operation is not deleting named ranges. So Ive tried to use Class NamedRanges and list trough them by name on second row and to remove them one by one but it doesn't work here is what I tried:
function CellNamerRemove()
{
// the purpose of the CellNamerRemove function is to automatically remove all range names the complete vertical CellRanges
// for each column that has a 'header' in the sheet called 'RawData'. The Quality purpose is to force
// Named-Links only to exist in referencing the raw data from the Starccm+ files
// get a reference to the RawData Spreadsheet
var thisSheetString = "RawData";
var maxRows = SpreadsheetApp.getActiveSheet().getMaxRows();
var lastColumn = SpreadsheetApp.getActiveSheet().getLastColumn();
// loop from 1st column ie 1 to lastColumn.
for(thisColumn = 1; thisColumn <= lastColumn;thisColumn++)
{
var thisName = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(thisSheetString).getRange(2, thisColumn, 1, 1).getValue();
var ss = SpreadsheetApp.getActiveSpreadsheet();
// ss.setNamedRange(trim(thisName), thisRange);
ss.getRangeByName(thisName).remove();
}
}
Can you help me with?
actually I prepared and ran this script which helped me remove ALL named ranges.
function removeNamedRanges(){
var namedRanges = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getNamedRanges();
for(i=0;i<namedRanges.length;i++){
namedRanges[i].remove();
}
}
The problem is in this line:
ss.getRangeByName(thisName).remove();
It should be:
ss.removeNamedRange(thisName);