Google Sheets Create new tab - google-apps-script

Need some advise on Google Sheets.
Sadly one of our clients uses Google Sheets as their Excel fix. As part of this one of the staff spends hours moving data about.
The first part of the problem is that we have a tab called master. In column A is a variable amount of cells (Some duplicates). We want to be able to create a new tab based on the distinct value in the cell (So one sheet per distinct value)
Now in Microsoft Excel VBA I can write this with my eyes closed, but on Google sheets I have no idea.
Any help is appreciated.

How about:
function createNewSheets() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var masterSheet = spreadsheet.getSheetByName('master');
// Retrieve 2d array for column A
var colA = masterSheet.getRange('A:A').getValues();
// Create a 1d array of unique values
var uniqueValues = {};
colA.forEach(function(row) {
row[0] ? uniqueValues[row[0]] = true : null;
});
var newSheetNames = Object.keys(uniqueValues);
newSheetNames.forEach(function(sheetName) {
// Check to see whether the sheet already exists
var sheet = spreadsheet.getSheetByName(sheetName);
if (!sheet) {
spreadsheet.insertSheet(sheetName);
}
});
}

Related

Google Sheets Auto Filter

I am trying to make an automated google sheet which will filter pending IDs on column P every 5 minutes to avoid reediting the entry.
So I tried to record a macro and put a trigger on it but the trigger didn't work. I am having an error of "setColumnFilterCriteria' of null at UntitledMacro(macros:7:43)"
The editors of the said file is about 10 people with editor restriction but are retricted on other columns. Hope you can help. Thanks in advance
Below were the codes of the macro recorder:
function UntitledMacro() {
var spreadsheet =
SpreadsheetApp.getActive();
spreadsheet.Getrange('P1').activate(); varcriteria=SpreadsheetApp.newFilterCriteria().setHiddenValues(['Completed', 'Other']).build(); spreadsheet.getActiveSheet().getFilter().setColumnFilterCriteria(16, criteria) ;
};
You encountered such error because your current active sheet doesn't have an existing filter. If there is no current filter in the sheet, getFilter() will return null. Hence setColumnFilterCriteria() don't exist.
As a workaround, you can include an if condition to check if the current sheet doesn't have any filter yet. Then create a new filter.
Sample Code:
function UntitledMacro() {
var spreadsheet = SpreadsheetApp.getActive();
Logger.log(spreadsheet.getActiveSheet().getFilter());
spreadsheet.getRange('P1').activate();
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(['Completed', 'Other']).build();
var filter = spreadsheet.getActiveSheet().getFilter();
if(filter){
filter.setColumnFilterCriteria(16, criteria);
}else{
//There is currently no filter in the selected sheet
//Create new filter in Cell P1
spreadsheet.getActiveSheet().getRange('P1:P').createFilter().setColumnFilterCriteria(16, criteria);
}
};

Google apps script for sheets, how to create a 2-way link between two spreadsheets?

I'm attempting to write a script to continuously update two spreadsheets so that the information put in one always goes into the other.
The full project is to create a master spreadsheet with 50 people on it and each one of them has their own sheet/page, however they aren't allowed to access this master sheet as they are not allowed to see the other peoples data. (I am currently unaware of any viewing permission commands but I'm pretty sure there aren't any).
So the solution that I have been considering is creating 50 other spreadsheets and each of them will have a single sheet with all of the same information as the master Spreadsheet and the name of the sheet will be the same as on the master page.
I found this code on another post that was for a similar problem
function onEdit(e) {
// Get the event object properties
var range = e.range;
var value = e.value;
//Get the cell position
var row = range.getRowIndex();
var column = range.getColumnIndex();
exportValue(row,column,value)
}
function exportValue(row,column,value) {
var ss = SpreadsheetApp.openById(targetID);
var s = ss.getSheetByName(targetSheetName);
var target = s.getRange(row, column);
target.setValue(value);
}
in this I understand what everything is doing except the ("var range = e.range; var value = e.value;") lines, is ths what im looking for or not, idk
Thanks in advance
:)

How to make google sheets index from values in column and hyperlink those to sheets

I have a bunch of data I want to put in to multiple sheets, and to do it manually would take time and I would like to learn scripting too.
So say I have a sheet with the states in one column.
I would like to have a script make new sheets based off the values of that column, and make a hyperlink to those sheets, and sort the sheets alphabetically.
In each sheet, I need to have the A1 cell the same name as the sheet.
Here is an example of states
Any suggestions would be helpful
Edit:
This is code that can make sheets based on the values of the columns.
function makeTabs() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var last = sheet.getLastRow();//identifies the last active row on the sheet
//loop through the code until each row creates a tab.
for(var i=0; i<last; i++){
var tabName = sheet.getRange(i+2,1).getValue();//get the range in column A and get the value.
var create = ss.insertSheet(tabName);//create a new sheet with the value
}
}
(note the "sheet.getRange(i+2,1" assumes a header, so pulls from the first column, starting on the second row)
I still need to:
Add a hyper link in the index sheet to the State's sheet: example: A2 on the Index sheet
would be =HYPERLINK("#gid=738389498","Alabama")
Also I need the A1 cell of the State's page to have the same info as
the index. example: Alabama's A1 cell would be =Index!A2
You could take a look at this script:
function createSheets(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var indexSheet = ss.getSheetByName('Index');
var indexSheetRange = indexSheet.getDataRange();
var values = indexSheetRange.getValues();
var templateSheet = ss.getSheetByName('TEMPLATE_the_state');
templateSheet.activate();
var sheetIds = [],
state,
sheetId,
links = [];
for (var i = 1 ; i < values.length ; i++){
state = values[i][0];
sheetId = undefined;
try{
var sheet = ss.insertSheet(state, {template: templateSheet});
SpreadsheetApp.flush();
sheet.getRange("A1:B1").setValues([['=hyperlink("#gid=0&range=A' +(i+1)+'","go back to index")',state]]);
sheetId = sheet.getSheetId();
}
catch (e) { Logger.log('Sheet %s already exists ' , sheet)}
sheetIds.push([sheetId,state]);
}
sheetIds.forEach(function(x){
links.push(['=HYPERLINK("#gid='+x[0]+'&range=A1","'+x[1]+'")']);
});
indexSheet.getRange(2,1,links.length,links[0].length).setValues(links) // in this case it is clear to us from the outset that links[0].length is 1, so we could have written 1
}
Note that in my version, I created a template sheet from which to base all the state sheets from. This wasn't what you asked for, but I wanted to see what it would do.
The resulting sheet is here: https://docs.google.com/spreadsheets/d/1Rk00eXPzkfov5e3D3AKOVQA2UdvE5b8roG3-WeI4znE/edit?usp=sharing
Indeed, I was surprised at how long it took to create the full sheet with all the states - more than 250 secs. I looked at the execution log, which I have added to the sheet in its own tab. There it is plain to see that the code is quick, but sometimes (why only sometimes, I don't know) adding a new tab to the spreadsheet and/or flushing the formulas on the spreadsheet is very slow. I don't know how to speed it up. Any suggestions welcome. (I could try the Google Sheets API v4, probably would be much faster ... but that is much more work and tougher to do.)

Script to copy data between sheets

I'm trying to create a script to copy data from sheet 1 to sheet 2 and at the same time reorder it. I get my data from a Google form, so data is constantly updating.
Here are two images as examples. N°1 is how I have my data, N°2 is how I want it to be in sheet 2.
The idea is to have the script copying the data every time a new row appears.
Data from Forms.
This is how I would like it to be.
This is my initial code:
function copyrange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Ingreso'); //source sheet
var testrange = sheet.getRange('J:J');
var testvalue = (testrange.getValues());
var csh = ss.getSheetByName('Auxiliar Ingreso'); //destination sheet
var data = [];
var columnasfijas = [];
var cadena = [];
//Condition check in G:G; If true copy the same row to data array
for (i=1; i<testvalue.length;i++) {
data.push.apply(data,sheet.getRange(i+1,1,1,9).getValues());
if ( testvalue[i] == 'Si') {
data = (sheet.getRange(i+1,1,1,9).getValues()).concat (sheet.getRange(i+1,11,1,9).getValues()); // this beaks up into 2 rows Idon't know why
/*cadena = (columnasfijas);
data.push.apply(data, columnasfijas);*/
}
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
}
//Copy data array to destination sheet
//csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
}
In this line, I'm also having trouble concatenating different lengths of data. It should be: (i+1,1,1,6). concat.....(i+1,11,1,3)
data = (sheet.getRange(i+1,1,1,9).getValues()).concat (sheet.getRange(i+1,11,1,9).getValues()); // this beaks up into 2 rows Idon't know why
When I run it as it should by I receive an error that the length should be 9 instead of 3.
This can be accomplished more simply using formulas instead of app scripts:
=sort(importrange("spreadsheetURL", "Sheet1!A2:AA10000"),sort_col#,TRUE/FALSE,[sort_col2#],[TRUE/FALSE]...)
Documentation on importrange function: https://support.google.com/docs/answer/3093340
Documentation on sort function: https://support.google.com/docs/answer/3093150
Once you input the formula, there will likely red triangle on the cell, be sure to click on the cell and click the Allow Access button to give one spreadsheet access to the other.

Google Sheets Filter Scripts

I am hoping that someone might be able to help me out, I've been doing a lot of searching in the past few days and coming up short of a solution. Likely has to do with my lack of knowledge on coding... I know enough to be dangerous, just not enough to be effective or efficient!
To start, here is my goal.
To create a document, that will contain a 'master list' of tasks for my marketing team.
Each team member (currently 4) will have their own tab, which would only display tasks assigned to their name & have blank spaces under both 'completed' and 'canceled' columns...
In addition to the team member tabs, there would be two others, 'Completed' and 'Canceled'. These tabs would contain any tasks, by any team member, that have a date under the respective column.
Currently, I managed to create a script that will delete all tabs (other than the master list) and recreate them with the assigned name. What I haven't been able to do is get each sheet to filter results. I can't seem to get any code that I've found in the forums to work. Nothing will filter the results automatically on any tab, it only copies the master list and renames the tabs. Can someone point me in the right direction?
Am I going about this in the most efficient way possible? Do I need a button that will run the script on command? Is there a way for the 'team member' sheets to update live based on what is entered into the master list? I tried to utilize this information (Filter data by column K in Google Script Editor (Google Sheets)) but was not able to make it function within my document.
Sorry for the lengthy, post, thanks in advance for any and all help!
A copy of the original file:
https://docs.google.com/spreadsheets/d/141JochDYmt9RHRnyaY2iIoyAISCNNXFVUvEtJlBwtiQ/edit?usp=sharing
Example of the code:
function RunFilters() {
var name = "Adam";
/*ADAM*/
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Marketing').copyTo(ss);
/* Before cloning the sheet, delete any previous copy */
var old_name = ss.getSheetByName(name);
if (old_name) ss.deleteSheet(old_name); // or old.setName(new Name);
SpreadsheetApp.flush();
sheet.setName(name);
/* Make the new sheet active */
ss.setActiveSheet(sheet);
function myFunction() {
var ss = SpreadsheetApp.getSheetByName('Marketing'); //replace with source Sheet tab name
var range = ss.getRange('A:I'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.getActiveSpreadsheet(); //replace with destination ID
var ts = tss.getSheetByName('Adam'); //replace with destination Sheet tab name
ts.getRange(ts.getLastRow() + 1, 1, data.length, data[0].length).setValues(data);
var range = ts.getRange(ts.getLastRow() + 1, 1, data.length, data[0].length)
var rawData = range.getValues() // get value from spreadsheet 2
var data = [] // Filtered Data will be stored in this array
for (var i = 0; i < rawData.length; i++) {
if(rawData[i][5] == "Adam") // Check to see if column K says ipad if not skip it
{
data.push(rawData[i])
}
}
}
}