Google Sheets - copy 2 spreadsheets into specific folder with specific name - google-apps-script

I have spreadsheet with multiple sheets inside. I'd like to make a macro which would copy two specific sheets into another spreadsheet and name it using format "MYNAME_YYYY_MM_DD" where YYYY_MM_DD is replaced with the date on which macro was ran.
So far i have this:
function X() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('INPUT'), true);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('OUTPUT'), true);
};

Copy two spreadsheets into a folder
function lfunko() {
const ss0 = SpreadsheetApp.openById("id0");
const ss1 = SpreadsheetApp.openById("id1");
const file0 = DriveApp.getFileById(ss0.getId());
const file1 = DriveApp.getFileById(ss1.getId());
const folder = DriveApp.getFolderById("folderid");
file0.makeCopy(`myname${Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"yyyy_MM_dd")}`,folder);
file0.makeCopy(`myname${Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"yyyy_MM_dd")}`,folder);
}

Related

Google Apps Script - How to Update Code to Have Tabs Containing the Same Word in Name Split Into the Same Google Sheets File?

I'm using the following code to turn tabs in a Google Sheets file into separate Google Sheets files. One challenge that I have is that there's some tabs that have similar names and I don't want to have separate Google Sheets files for them.
For ex: Say there's 5 tabs in the Google Sheets file: tab1: 'Toys Check', tab2: 'Toys Checked', tab3: 'Clothes Check', tab4: 'Video Games Check', tab5: 'Video Games Checked'. Right now, the below code will create 5 separate Google Sheet's files for them. However, I want the code to create 3 separate Google Sheets files instead. The first Google Sheets file would contain 2 tabs: tab1: 'Toys Check' and tab2: 'Toys Checked'. The second Google Sheets file would just have 'Clothes Check' tab. The third Google Sheets file would also contain 2 tabs: tab1: 'Video Games Check' and tab2: 'Video Games Checked'.
Below is a visual of the above example:
How can the below code be updated to ensure that tabs that have the same name (minus the 'check' or 'checked' part of the tab name) would end up being split into the same Google Sheets file? For the file name, is it possible to make it so that it is the same as the unique category + 'Summary'. So in the above example, the file name for the Google Sheets file that contains 'Toys Check' and 'Toys Checked' tabs would be 'Toys Summary'.
function copySheetsToFolder() {
var ss = SpreadsheetApp.getActive();
var folderId = DriveApp.getFileById(ss.getId()).getParents().next().getId();
for (var n in ss.getSheets()) {
var sheet = ss.getSheets()[n];
var name = sheet.getName();
if (name != 'ControlTab' && name != 'RawData') {
var alreadyExist = DriveApp.getFilesByName(name);
while (alreadyExist.hasNext()) {
alreadyExist.next().setTrashed(true);
}
var newSS = Drive.Files.insert({ title: name, mimeType: MimeType.GOOGLE_SHEETS, parents: [{ id: folderId }] }, null, { supportsAllDrives: true });
var copy = SpreadsheetApp.openById(newSS.id);
sheet.copyTo(copy).setName(name);
copy.deleteSheet(copy.getSheets()[0]);
}
}
}
I believe your goal is as follows.
You want to achieve a goal shown in your question using Google Apps Script.
The suffix of the sheet names are always Check or Checked.
You want to give the new Spreadsheet names like ### Summary.
From your showing script, you want to remove the existing Spreadsheets in the parent folder of the active Spreadsheet.
In this case, how about the following sample script?
Sample script:
function myFunction() {
const exclude = ['ControlTab', 'RawData']; // This is from your showing script.
const suffix = ["Checked", "Check"]; // This is from your comment.
const newSuffix = "Summary"; // This is from your question.
// Retrieve active Spreadsheet.
const ss = SpreadsheetApp.getActiveSpreadsheet();
// Create an object for creating new Spreadsheets by splitting sheets.
const obj = ss.getSheets().reduce((o, s) => {
const name = s.getSheetName();
if (!exclude.includes(name)) {
const n = name.replace(new RegExp(suffix.join("|")), "").trim();
o[n] = o[n] ? [...o[n], s] : [s];
}
return o;
}, {});
// Retrieve files from the parent folder and create a file object.
const folder = DriveApp.getFileById(ss.getId()).getParents().next();
const files = folder.getFilesByType(MimeType.GOOGLE_SHEETS);
const fileObj = {};
while (files.hasNext()) {
const f = files.next();
fileObj[f.getName()] = f;
}
// Create new Spreadsheets including several sheets.
Object.entries(obj).forEach(([ssName, sheets]) => {
const newSSName = `${ssName} ${newSuffix}`;
if (fileObj[newSSName]) {
fileObj[newSSName].setTrashed(true);
}
const newss = SpreadsheetApp.create(newSSName);
sheets.forEach(s => s.copyTo(newss).setName(s.getName()));
newss.deleteSheet(newss.getSheets()[0]);
DriveApp.getFileById(newss.getId()).moveTo(folder);
});
}
The variables exclude, suffix and newSuffix are from your question and your comment.
When this script is run, several new Spreadsheets including several sheets are created in the same folder of the active Spreadsheet. Each sheet in a Spreadsheet is retrieved from the sheet name.
References:
reduce()
forEach()

Naming a New Sheet with Google Scripts from a specific cell on a Google Sheet

trying to figure out how to give a new sheet that is copied into a folder a specific name each time from a button script. The specific name would come from a specific cell each time.
Here's the current code being used and the New Sheet is what I'm trying to have named from cell B3 on a specific spreadsheet each time. No idea how to do this, it just names it NEW SHEET each time and then errors out when I try to do B3.
function cloneGoogleSheet() {
var destFolder = DriveApp.getFolderById("Folder Name");
DriveApp.getFileById("Folder Name").makeCopy('NEW SHEET', destFolder);
SpreadsheetApp.getActive().getSheetByName('NEW SHEET').setName('Specific Sheet!B3')
}
Any help is appreciated!
function cloneGoogleSheet() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const name = sh.getRange('A1').getDisplayValue();
const destFolder = DriveApp.getFolderById("Folder Id");
DriveApp.getFileById("file id").makeCopy(name, destFolder);
}
Get used to using file id's and not names.

Get Folder Name in google apps script

I am currently creating a script file bounded to a spreadsheet, where this spreadsheet is stored in a folder. Now, I need the name of the folder in which this spreadsheet exists. So how do I achieve this?
Solution:
The following script will get the name of the parent folder of the bound spreadsheet and set it to cell A1. Adjust the script to your needs.
function myFunction() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1');
const ss_id = ss.getId();
const file = DriveApp.getFileById(ss_id);
const parent_folders = file.getParents()
const folder_name = parent_folders.next().getName(); //desired result
sh.getRange('A1').setValue(folder_name);
}
folder_name is the name of the parent folder of the existing spreadsheet.

Merge n Google spreadsheets files to n sheets

Say, I have 100 google spreadsheets file and I need to merge into one file with 100 tabs(sheets). Is it possible with app script. Currently I have a code below,
function popForm() {
var ss = SpreadsheetApp.getActive();
for(var b = 0; b<100; b++){
var sheet = ss.getSheetByName('Sheet '+b);
var numberRows = sheet.getDataRange().getNumRows();
....
....
The above code will work with spreadsheets with 100 tabs(Sheets). But I have 100 sreadsheets with one tab(Sheet).
Explanation:
You have a folder with FolderId that contains all the spreadsheet
files. You find this folder using the getFolderById() method.
You get the files of this folder using the getFiles() method and
you use a while loop to iterate over these files.
For every file, you get the first sheet and you copy it using the
copyTo() method to the source (active) spreadsheet file.
The newly create sheet will be named after the name of the spreadsheet file that it came from. Feel free to change this part or let me know so I can modify it.
Solution:
You must be looking for this:
function myFunction() {
const source_sh = SpreadsheetApp.getActive();
const folder = DriveApp.getFolderById('FolderId');
const files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
var target_ss = SpreadsheetApp.openById(file.getId());
var target_sh = target_ss.getSheets()[0];
target_sh.copyTo(source_sh).setName(file.getName());
}
}

How to create hyperlink to range in Google Sheets App Script?

I'm trying to fill cells with hyperlinks to ranges in Google Sheets app script with the same desired outcome I would get had I done it in GUI. I managed to create hyperlinks to sheet in the form of "gid=..." with the ... being a sheetID. But I struggle to get the rangeID that is used when generating the hyperlink in GUI e.g.
HYPERLINK("#rangeid=1420762593";"'List 4'!F2:F15")
Is it possible to create hyperlinks to ranges in app script?
Yes, you can do this in App Script. Here's a very simple implementation where the HYPERLINK function is built and appended to a cell:
function hyperlinkRange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Sheet1");
var sheet2 = ss.getSheetByName("Sheet2").getSheetId();
sheet1.getRange("A1").setValue('=hyperlink("#gid='+sheet2+'&range='+sheet1.getRange('A1:A10').getA1Notation()+'", "Click to jump to Sheet 2")');
}
You can combine this with loops to set a value of links across multiple sheets.
Custom functions
Use in a formula.
Simple range:
=HYPERLINK(getLinkByRange("Sheet1","A1"), "Link to A1")
Named range:
=HYPERLINK(getLinkByNamedRange("NamedRange"), "Link to named range")
The code, insert into the script editor (Tools > Script Editor):
function getLinkByRange(sheetName, rangeA1, fileId)
{
// file + sheet
var file = getDafaultFile_(fileId);
var sheet = file.getSheetByName(sheetName);
return getCombinedLink_(rangeA1, sheet.getSheetId(), fileId, file)
}
function getLinkByNamedRange(name, fileId)
{
// file + range + sheet
var file = getDafaultFile_(fileId);
var range = file.getRangeByName(name);
var sheet = range.getSheet();
return getCombinedLink_(range.getA1Notation(), sheet.getSheetId(), fileId, file)
}
function getDafaultFile_(fileId)
{
// get file
var file;
if (fileId) { file = SpreadsheetApp.openById(fileId); }
else file = SpreadsheetApp.getActive();
return file;
}
function getCombinedLink_(rangeA1, sheetId, fileId, file)
{
var externalPart = '';
if (fileId) { externalPart = file.getUrl(); }
return externalPart + '#gid=' + sheetId + 'range=' + rangeA1;
}
Here is another example. Hopefully, it is clean and self-explanatory
function hyperlinkRange(shDest,rgDest,shSrc,rgSrc,linkText) {
// get the spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet()
// get the destination sheet id
var idDest = shDest.getSheetId()
// link the range
var formula = '=hyperlink("#gid='+idDest+'&range='+rgDest+'","'+linkText+'")'
shSrc.getRange(rgSrc).setValue(formula)
}
In case you want to create a link to another sheet which will open the sheet in the same browser tab here is what you want to do:
1. Get the id of the sheet. Check the link in your browser and you will see #gid=x where x is the sheet id
2. Then you want to set the formula (hyperlink) to the cell and make it show as a hyperlink
SpreadsheetApp.getActiveSheet().getRange("A1").setFormula('=HYPERLINK("#gid=X","test")').setShowHyperlink(true);
If you don't use setShowHyperlink(true) it will be shown as a regular text.