I have 10 to 15 Files in the Drive Folder All files have more than 1 Google sheets in it with some sort of Conditional Formatting.
I want to copy the Specific Sheet Named "MasterSheet" from each File and Combine the data into the Active Sheet where from script is bieng run.
Copied data should keep conditional formatting cell color. I will appreciate the help. Thanks
function myFunction()
{
var myFolder = DriveApp.getFolderById("FolderID");
var spreadSheets = myFolder.getFilesByType("application/vnd.google-apps.spreadsheet");
var ActiveSpreadSheet = SpreadsheetApp.getActive().getSheetByName(Sheet1);
while(spreadSheets.hasNext())
{
var sheet = spreadSheets.next();
var spreadSheet = SpreadsheetApp.openById(sheet.getId());
for(var y in spreadSheet.getSheets())
{
spreadSheet.getSheets()[y].copyTo(ActiveSpreadSheet);
}
}
}
UPDATE to check if there's a sheet called that way:
function copywithLog()
{
var destinsheet = SpreadsheetApp.getActiveSpreadsheet()
var myFolder = DriveApp.getFolderById("16CxTO70ipcUt8U_beokid3vFOOLGTnPh");
var spreadSheets = myFolder.getFilesByType("application/vnd.google-apps.spreadsheet");
var activeSpreadSheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var i = 1
while(spreadSheets.hasNext())
{
var sheet = spreadSheets.next();
var spreadSheet = SpreadsheetApp.openById(sheet.getId());
var sheets = spreadSheet.getSheets()
var filtered = sheets.filter(n => ["DATA"].lastIndexOf(n.getSheetName()) == 0)
if (filtered.length==1){
var newsheet = spreadSheet.getSheetByName('DATA').copyTo(destinsheet)
newsheet.getDataRange().copyTo(activeSpreadSheet.getRange(activeSpreadSheet.getLastRow()+2,1))
destinsheet.deleteSheet(newsheet)
Logger.log("Process successfully finished with the workbook named '"+spreadSheet.getName()+"'")}
else Logger.log("The worbook named '"+spreadSheet.getName()+ "' does not have a sheet called DATA")
}
}
It returns something like this:
UPDATE:
function copyinsamesheet()
{
var destinsheet = SpreadsheetApp.getActiveSpreadsheet()
var myFolder = DriveApp.getFolderById("FolderID");
var spreadSheets = myFolder.getFilesByType("application/vnd.google-apps.spreadsheet");
var activeSpreadSheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var i = 1
while(spreadSheets.hasNext())
{
var sheet = spreadSheets.next();
var spreadSheet = SpreadsheetApp.openById(sheet.getId());
var newsheet = spreadSheet.getSheetByName('MasterSheet').copyTo(destinsheet)
newsheet.getDataRange().copyTo(activeSpreadSheet.getRange(activeSpreadSheet.getLastRow()+2,1))
destinsheet.deleteSheet(newsheet)
}
}
If it has always the same name, you can try with this:
function copyMasterSheets()
{
var destinsheet = SpreadsheetApp.getActiveSpreadsheet()
var myFolder = DriveApp.getFolderById("FolderID");
var spreadSheets = myFolder.getFilesByType("application/vnd.google-apps.spreadsheet");
var ActiveSpreadSheet = SpreadsheetApp.getActive().getSheetByName(Sheet1);
var i = 1
while(spreadSheets.hasNext())
{
var sheet = spreadSheets.next();
var spreadSheet = SpreadsheetApp.openById(sheet.getId());
spreadSheet.getSheetByName('MasterSheet').copyTo(destinsheet).setName('MasterSheet '+i)
i++
}
}
An addendum to the answer by #Martin.
This takes the data on the various "Master Sheets" and copies it to a single sheet.
The range of data on each sheet is established dynamically, and is stacked down the page.
function copyMasters(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var target = ss.getSheetByName('Sheet1')
// idetify the starting row
var activeStartRow = 1
// get an array of all the sheets with names like "MasterSheet"
var sheetList = new Array
var sheets = ss.getSheets()
//var sourcesheet = ss.getSheets().find(sheet => sheet.getName().includes("MasterSheet"))
var mastersheets = sheets.filter(sheet => sheet.getName().includes("MasterSheet"))
//loop through the Master sheets
for (var i=0;i<mastersheets.length;i++){
var mastername = mastersheets[i].getName()
var master = ss.getSheetByName(mastername)
var masterLC = master.getLastColumn()
var masterLR = master.getLastRow()
// calculate the start row for the target sheet
if (activeStartRow==1){
var startRow =1
}else{
var startRow=startRow+masterLR
}
activeStartRow = 0
var rangeToCopy = master.getRange(1, 1, masterLR,masterLC)
//Logger.log("DEBUG: range to copy:"+rangeToCopy.getA1Notation())
var targetRange = target.getRange(startRow, 1, masterLR,masterLC)
//Logger.log("DEBUG: target range:"+targetRange.getA1Notation())
rangeToCopy.copyTo(targetRange)
// Logger.log("DEBUG: copied the data for "+mastername)
}
}
SAMPLE
Related
I am trying to import data from a specific URL into all sheets that are in a Google drive folder, then only keep the data that contains the name of the file.
Getting the files from the folder seems to be working but I cannot manage to have SpreasheetApp working (I think this is where the problem comes from). Maybe there is something wrong with how I manage to get ranges.
Here is what I have done so far :
function myfunction()
{
var root = DriveApp.getFoldersByName("Produits");
while (root.hasNext())
{
var folder = root.next(); //If the folder is available, get files in the folder
var files = folder.getFiles();
while(files.hasNext()) //For each file,
{
var spreadsheet = SpreadsheetApp.open(files.next());
//import data from URL
var csvUrl = "myURL";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var activeSpreadSheet = SpreadsheetApp.open(files);
var sheets = activeSpreadSheet.getSheets();
var sheet = sheets[sheetIndex]
sheet.getRange(2, 1, csvData.length, csvData[0].length).setValues(csvData);
// Always show 3 decimal points
var cell = sheet.getRange("D2:D");
cell.setNumberFormat("00");
//Only keep data that contains the file name
var name = sheet.getName();
let range = sheet.getDataRange(),
maxRows = sheet.getMaxRows(),
srchCol_1 = 2,
srchPatt_1 = new RegExp(name)
newRangeVals = range.getValues().filter(r => r[0] && srchPatt_1.exec(r[srchCol_1])),
numRows = newRangeVals.length;
range.clearContent();
sheet.getRange(2,1, numRows, newRangeVals[0].length).setValues(newRangeVals);
sheet.deleteRows(numRows + 1, maxRows - numRows);
//Clean headers
var cell = sheet.getRange(1,1);
cell.setValue("Marchand");
var cell = sheet.getRange(1,2);
cell.setValue("Image");
var cell = sheet.getRange(1,3);
cell.setValue("Titre de l'offre");
var cell = sheet.getRange(1,4);
cell.setValue("Prix");
var cell = sheet.getRange(1,5);
cell.setValue("Lien");
var cell = sheet.getRange(1,6);
cell.setValue("Categorie");
}
}
}
Change
var activeSpreadSheet = SpreadsheetApp.open(files);
var sheets = activeSpreadSheet.getSheets();
to (spreadsheet has already been defined previously)
var sheets = spreadsheet.getSheets()
and give a value to sheetIndex, for instance
var sheets = spreadsheet.getSheets();
var sheetIndex=0
var sheet = sheets[sheetIndex]
I want to copy the range of values from one spreadsheet to another (A1:H45). I tried the code below. In spite of copying the values of Cells A1:H45, its copying A1 Cell data in a new sheet throughout A1:H45, which means the same data getting copied 45 times.
function Copy()
{
var sss = SpreadsheetApp.openById('1IK6YsZS3_NNAlFA41d8uKriPzfZs_2Ukyh94eeBFj40');
var ss = sss.getSheetByName('CURRENT');
var range = ss.getRange('A1:H45');
var data = range.getValues();
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var yourNewSheet = activeSpreadsheet.getSheetByName("New sheet");
if (yourNewSheet != null)
{
activeSpreadsheet.deleteSheet(yourNewSheet);
}
yourNewSheet = activeSpreadsheet.insertSheet();
yourNewSheet.setName("Name of your new sheet");
yourNewSheet.getRange(yourNewSheet.getLastRow()+1,1,45,8).setValue(data);
}
Try this -
function Copy()
{
var sss = SpreadsheetApp.openById('1IK6YsZS3_NNAlFA41d8uKriPzfZs_2Ukyh94eeBFj40');
var ss = sss.getSheetByName('CURRENT');
var range = ss.getRange('A1:H45');
var data = range.getValues();
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var yourNewSheet = activeSpreadsheet.getSheetByName("New sheet");
if (yourNewSheet != null)
{
activeSpreadsheet.deleteSheet(yourNewSheet);
}
yourNewSheet = activeSpreadsheet.insertSheet();
yourNewSheet.setName("Name of your new sheet");
yourNewSheet.getRange(yourNewSheet.getLastRow()+1,1,45,8).setValues(data);
}
Your code is perfect. All you had to do was use setValues (plural) instead of setValue :)
I want to accomplish the following:
Make a menu with a print to PDF button.
Have that button export a PDF to with the same name and same destination as the google sheet.
This works well, but the script I found I need to change, because most people print to PDF by making a temporary copy of the sheet, printing, and finally deleting the temporary copy.
I have references from other sheets in my original document that ends up printed as #REF! values because only the one sheet gets copied and printed, not my whole document.
How can i make this process include baking the formulas as text?
CODE FOR PRINTING:
function onOpen() {
var submenu = [{name: "Save PDF", functionName: "generatePdf"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu('Export', submenu);
}
function generatePdf() {
// Get active spreadsheet.
var sourceSpreadsheet = SpreadsheetApp.getActive();
// Get active sheet.
var sheets = sourceSpreadsheet.getSheets();
var sheetName = sourceSpreadsheet.getActiveSheet().getName();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
// Set the output filename as sheetName.
var pdfName = sheetName;
// Get folder containing spreadsheet to save pdf in.
var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
}
else {
folder = DriveApp.getRootFolder();
}
// Copy whole spreadsheet.
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder))
// Delete redundant sheets.
var sheets = destSpreadsheet.getSheets();
for (i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() != sheetName){
destSpreadsheet.deleteSheet(sheets[i]);
}
}
var destSheet = destSpreadsheet.getSheets()[0];
// Replace cell values with text (to avoid broken references).
var sourceRange = sourceSheet.getRange(1, 1, sourceSheet.getMaxRows(), sourceSheet.getMaxColumns());
var sourcevalues = sourceRange.getValues();
var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
destRange.setValues(sourcevalues);
// Save to pdf.
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
// Delete the temporary sheet.
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}
CODE FOR CONVERTING FORMULAS TO TEXT:
function formulasAsText() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var k = 0; k < sheets.length; k++) {
var range = sheets[k].getDataRange();
var values = range.getValues();
var formulas = range.getFormulas();
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[0].length; j++) {
values[i][j] = formulas[i][j] ? "'" + formulas[i][j] : values[i][j];
}
}
range.setValues(values);
}
}
To maintain formula references, you need to modify the formulasAsText() function to accept an input, and also not worry about writing a formula if one is found. This input could be a spreadsheet ID - i.e. the id of the temporary copy - or it could be an array of Sheet objects.
Once you have made these two modifications, you would call the function prior to deleting the non-desired sheets in the temporary copy:
/**
* #param Sheet[] wbSheets An array of Sheets to operate on.
* #param String toPreserve The name of the sheet which should be preserved.
*/
function preserveFormulas(wbSheets, toPreserve) {
if(!wbSheets || !wbSheets.length || !toPreserve)
throw new Error("Missing arguments.");
wbSheets.forEach(function (sheet) {
if ( sheet.getName() === toPreserve ) {
var range = sheet.getDataRange();
// Serialize the cell's current value, be it static or derived from a formula.
range.setValues(range.getValues());
}
});
}
Finished my script. Here is what i ended up with.
function onOpen() {
var submenu = [{name:"Save PDF", functionName:"generatePdf"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu('Export', submenu);
}
function hideSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("sheet1");
var sheet2 = ss.getSheetByName("PRINT SHEET");
var sheet3 = ss.getSheetByName("sheet3");
var sheet4 = ss.getSheetByName("sheet4");
var sheet5 = ss.getSheetByName("sheet5");
var sheet6 = ss.getSheetByName("sheet6");
var sheet7 = ss.getSheetByName("sheet7");
sheet1.hideSheet();
sheet3.hideSheet();
sheet4.hideSheet();
sheet5.hideSheet();
sheet6.hideSheet();
sheet7.hideSheet();
}
function showSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("sheet1");
var sheet2 = ss.getSheetByName("PRINT SHEET");
var sheet3 = ss.getSheetByName("sheet3");
var sheet4 = ss.getSheetByName("sheet4");
var sheet5 = ss.getSheetByName("sheet5");
var sheet6 = ss.getSheetByName("sheet6");
var sheet7 = ss.getSheetByName("sheet7");
sheet1.showSheet();
sheet3.showSheet();
sheet4.showSheet();
sheet5.showSheet();
sheet6.showSheet();
sheet7.showSheet();
}
function generatePdf() {
// Get active spreadsheet.
var sourceSpreadsheet = SpreadsheetApp.getActive();
// Get active sheet.
var sheets = sourceSpreadsheet.getSheets();
var sheetName = sourceSpreadsheet.getActiveSheet().getName();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
// Set the output filename as BID and number (from cell C4).
var pdfName = "BID " + sheets[0].getRange("C4").getValue() + ".pdf";
var ui = SpreadsheetApp.getUi();
// Get folder containing spreadsheet to save pdf in.
var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
}
else {
folder = DriveApp.getRootFolder();
}
hideSheets();
// Save to pdf.
var theBlob = sourceSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
showSheets();
ui.alert('Export finished');
}
Thanks.
in Google Sheets I have to repeat a function because getSheetByName() does not accept an array of sheets, it only accepts one sheet.
Is there a way to have one function that loops through specified sheets (not all sheets)?
i.e.
("Sheet1", "Sheet2" ) etc.
function recordHistory_1() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var source = sheet.getRange("A2:B2");
var values = source.getValues();
values[0][0] = new Date();
sheet.appendRow(values[0]);
};
function recordHistory_2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet2");
var source = sheet.getRange("A2:B2");
var values = source.getValues();
values[0][0] = new Date();
sheet.appendRow(values[0]);
};
Reason I'm asking is because I have over 20 sheets, and so I have to write this function 20 times...
You can generalize / reuse the same function for 20 different calls as follows.
var sheetListArray = ["Sheet1", "Sheet2", "Sheet3"......"Sheet20"]
var ss = SpreadsheetApp.getActiveSpreadsheet();
for( var i = 1 ; i <= sheetListArray.length ; i++)
// You can call the below function 20 time with different Sheet name each time.
recordHistory(sheetListArray[i]);
}
function recordHistory(sheetName) {
var sheet = ss.getSheetByName(sheetName);
var source = sheet.getRange("A2:B2");
var values = source.getValues();
values[0][0] = new Date();
sheet.appendRow(values[0]);
}
You can also call the function once and loop through an array of sheetnames inside the function.
function recordHistory() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
["Sheet1", "Sheet2", "Sheet3"].forEach(function (s) {
var sheet = ss.getSheetByName(s);
var values = sheet.getRange('A2:B2').getValues()
values[0][0] = new Date();
sheet.appendRow(values[0]);
})
}
I have had some help with the last line of this code and it works perfectly for a single sheet in the spreadsheet, however I have 5 sheets in the From spreadsheet and identical 5 sheets in the target spreadsheet how can I get the same range in the other 4 sheets to their same named counterpart in the target sheet? So I used below to try and copy each sheet to its corresponding namesake but I have set up the code as below but only importing the first sheet, also is there a way to only need to enter the originating spreadsheet id once for the whole code instead of at each sheet section?
function ImportDataRange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('AM trip'); //To Sheet Name
var ssraw = SpreadsheetApp.openById('1Z0zU2oGktLPB-QitYMm9XtOGN4Rd-Z-UJJomGX4NIO0'); // From Spreadsheet ID
var sheetraw = ssraw.getSheetByName('AM trip'); // From Sheet name
var range = sheetraw.getRange('B7:U38');
var data = range.getValues();
var lastRow = sheet.getLastRow()+1;
sheet.getRange(lastRow,3,data.length,data[0].length).setValues(data)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('PM trip'); //To Sheet Name
var ssraw = SpreadsheetApp.openById('1Z0zU2oGktLPB-QitYMm9XtOGN4Rd-Z-UJJomGX4NIO0'); // From Spreadsheet ID
var sheetraw = ssraw.getSheetByName('PM trip'); // From Sheet name
var range = sheetraw.getRange('B7:U38');
var data = range.getValues();
var lastRow = sheet.getLastRow()+1;
sheet.getRange(lastRow,3,data.length,data[0].length).setValues(data)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Pool / Beach'); //To Sheet Name
var ssraw = SpreadsheetApp.openById('1Z0zU2oGktLPB-QitYMm9XtOGN4Rd-Z-UJJomGX4NIO0'); // From Spreadsheet ID
var sheetraw = ssraw.getSheetByName('Pool / Beach'); // From Sheet name
var range = sheetraw.getRange('B7:U38');
var data = range.getValues();
var lastRow = sheet.getLastRow()+1;
sheet.getRange(lastRow,3,data.length,data[0].length).setValues(data)
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Night Dive'); //To Sheet Name
var ssraw = SpreadsheetApp.openById('1Z0zU2oGktLPB-QitYMm9XtOGN4Rd-Z-UJJomGX4NIO0'); // From Spreadsheet ID
var sheetraw = ssraw.getSheetByName('Night Dive'); // From Sheet name
var range = sheetraw.getRange('B7:U38');
var data = range.getValues();
var lastRow = sheet.getLastRow()+1;
sheet.getRange(lastRow,3,data.length,data[0].length).setValues(data)
}
Thank you for any help. Much appreciated.
The code can be simplified using a loop.
You said above that you have 5 sheets but you only have 4 in the code sample, add the other sheet name to var sheetNames.
function onOpen() { // This function adds a custom menu to the spreadsheet (Backup to archive) so you can run the script from there.
var ui = SpreadsheetApp.getUi();
ui.createMenu('Backup to archive')
.addItem('Backup', 'dataBackup')
.addToUi();
}
function dataBackup() {
var inputSS = SpreadsheetApp.openById('1wglM4-5jx873vwtFRPVgC1qk27JjrsYjDwp0fNpl5Xg'); // The file ID of the Input sheet
var archiveSS = SpreadsheetApp.openById('146WU8RghfFqlCpCSX7n6kBAKOyxcpVKt14yhVfvYz-g'); // The file ID of the archive sheet
// The names of the sheets to be copied.
// NOTE: These names must match the names of the sheets in BOTH spreadsheets i.e. the same case the spelling and the same spaces.
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
for (var i = 0; i < sheetNames.length; i++) { // Loop to each sheet listed in 'var sheetNames' and copy the data.
var inputSheet = inputSS.getSheetByName(sheetNames[i]);
var archiveSheet = archiveSS.getSheetByName(sheetNames[i]);
var data = inputSheet.getRange('B7:U38').getValues();
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 2, data.length, data[0].length).setValues(data);
}
}