Copy/paste values and formats while asking for name - google-apps-script

I am trying to copy over all of the values and formats to a different spreadsheet, week by week, creating a new sheet within the workbook each time. This is for archival purposes. I have pieced together the following:
function ArchiveByWeek(){
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('CRS Stats By Week')
var buildVersion = Browser.inputBox("What is the Weekend Ending Date?");
var sValues = source.getDataRange().getValues();
var sBG = source.getDataRange().getBackgrounds();
var sFC = source.getDataRange().getFontColors();
var sFF = source.getDataRange().getFontFamilies();
var sFL = source.getDataRange().getFontLines();
var sFFa = source.getDataRange().getFontFamilies();
var sFSz = source.getDataRange().getFontSizes();
var sFSt = source.getDataRange().getFontStyles();
var sFW = source.getDataRange().getFontWeights();
var sHA = source.getDataRange().getHorizontalAlignments();
var sVA = source.getDataRange().getVerticalAlignments();
var sNF = source.getDataRange().getNumberFormats();
var sWR = source.getDataRange().getWraps();
var destination = SpreadsheetApp.openById('1WVfJGDbdOewO2H-aMhQiek7sCOolK6xH7cSbfZ8KQgY');
var destinationSheet = destination.insertSheet(buildVersion, 1);
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues)
.setBackgrounds(sBG)
.setFontColors(sFC)
.setFontFamilies(sFF)
.setFontLines(sFL)
.setFontFamilies(sFFa)
.setFontSizes(sFSz)
.setFontStyles(sFSt)
.setFontWeights(sFW)
.setHorizontalAlignments(sHA)
.setVerticalAlignments(sVA)
.setNumberFormats(sNF)
.setWraps(sWR);
}
This seems to work fine, only some cells are not copied. For some reason, it is only cells that are summing other cells. Can't figure out why.
I found the following script, which worked perfectly, only I was unable to find a way to give each new sheet a unique name:
function copySheetValues(){
var source = SpreadsheetApp.getActiveSheet();
var sourcename = source.getSheetName();
var sValues = source.getDataRange().getValues();
var sBG = source.getDataRange().getBackgrounds();
var sFC = source.getDataRange().getFontColors();
var sFF = source.getDataRange().getFontFamilies();
var sFL = source.getDataRange().getFontLines();
var sFFa = source.getDataRange().getFontFamilies();
var sFSz = source.getDataRange().getFontSizes();
var sFSt = source.getDataRange().getFontStyles();
var sFW = source.getDataRange().getFontWeights();
var sHA = source.getDataRange().getHorizontalAlignments();
var sVA = source.getDataRange().getVerticalAlignments();
var sNF = source.getDataRange().getNumberFormats();
var sWR = source.getDataRange().getWraps();
var destination = SpreadsheetApp.openById('15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ');
var destinationSheet = destination.insertSheet(sourcename, 0);
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues)
.setBackgrounds(sBG)
.setFontColors(sFC)
.setFontFamilies(sFF)
.setFontLines(sFL)
.setFontFamilies(sFFa)
.setFontSizes(sFSz)
.setFontStyles(sFSt)
.setFontWeights(sFW)
.setHorizontalAlignments(sHA)
.setVerticalAlignments(sVA)
.setNumberFormats(sNF)
.setWraps(sWR);
}

I was actually able to come up with a solution that I was satisfied with. This was able to paste all of the values, and formats exactly as they were on the sheet when viewing. It asks for a name of the new sheet, which was my intention:
function Archive() {
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('SHEET NAME')
var sValues = source.getDataRange()
.getValues();
var weekEnding = Browser.inputBox("What is the Weekend Ending Date?");
var destination = SpreadsheetApp.openById('SHEET ID');
var copy = source.copyTo(destination)
.setName(weekEnding)
copy.getRange(1, 1, sValues.length, sValues[0].length)
.setValues(sValues); // overwrite all formulas that the copyTo preserved

Related

Script not finishing and error deletes the ranges that already ran

For some reason this script will run through exactly how I want it to. Then it will continue to load, then delete half the ranges that I have put into the cells and come up with the error:
"TypeError: Cannot read properties of undefined (reading 'getRange')
newSheet
# New sheet.gs:11"
Why would this happen if the script runs perfectly? The getRange is reading in line 11 or it wouldn't run the script correctly at first. I tried putting this into a new script window to see if it is just a fluke but that did not help.
function newSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
const templateSheet = ss.getSheetByName("Template");
var sheetName = templateSheet.getRange("G1").getValue();
templateSheet.copyTo(ss).setName("F"+sheetName);
var ods = ss.getSheetByName("F"+sheetName);
var ds = SpreadsheetApp.openById("1meEEfjXuOKQ3jCZi2wwmvz7CH83crsPzgnhOEC0rDhI");
var sheet = ds.getSheets();
for (var i=0;i<=sheet.length;i++){
var sheets = sheet[i]
var range = sheets.getRange("A1").getValue();//this is the spot that is getting the error
var label = templateSheet.getRange("A1").getValue();
var values1 = sheets.getRange("A9:B14").getValues();
var values2 = sheets.getRange("G8").getValues();
var values3 = sheets.getRange("A17:A22").getValues();
var values4 = sheets.getRange("A25:A32").getValues();
var values5 = sheets.getRange("A34:G44").getValues();
var values6 = sheets.getRange("A45:A49").getValues();
var values7 = sheets.getRange("A52:A58").getValues();
var values8 = sheets.getRange("A62:A67").getValues();
var values9 = sheets.getRange("E69:E74").getValues();
var values10 = sheets.getRange("E100:E103").getValues();
var values11 = sheets.getRange("H100:H101").getValues();
if(range==label){
ods.getRange("A9:B14").setValues(values1);
ods.getRange("G8").setValues(values2);
ods.getRange("A17:A22").setValues(values3);
ods.getRange("A25:A32").setValues(values4);
ods.getRange("A34:G44").setValues(values5);
ods.getRange("A45:A49").setValues(values6);
ods.getRange("A52:A58").setValues(values7);
ods.getRange("A62:A67").setValues(values8);
ods.getRange("E69:E74").setValues(values9);
ods.getRange("E100:E103").setValues(values10);
ods.getRange("H100:H101").setValues(values11);
}
}
}

Starting row of the range is too small

I have an issue that I cannot figure out. I wrote some code to take an item from a sheet called "Bag Label" and then look up its location in another sheet called "Inventory & Lots". and then to copy some of the cells to the right of that location.
It works well as long as the location is not row 80 or higher in sheet "Inventory & Lots". For the life of me, I cannot figure out why row 1 to 79 works but not 80+.
var ss=SpreadsheetApp.getActiveSpreadsheet();
var menuSheet=ss.getSheetByName("Bag Label");
var inventorySheet = ss.getSheetByName("Registered Lots");
var inventorySheetData = ss.getSheetByName("RegisteredLots - NO DEL");
var nextRow = inventorySheetData.getLastRow()+1;
var inventoryLots = ss.getSheetByName("Inventory & Lots");
var inventoryCalc = ss.getSheetByName("Inventory Calculation");
var inventoryCalcData = inventoryCalc.getRange(2,1,inventoryCalc.getLastRow()-1,4).getValues()
var inventoryData = inventoryLots.getRange(1,1,inventoryLots.getLastRow()-1,10).getValues()
var columnIndex = 0
var matchText = menuSheet.getRange("D2").getValue()
var kgNeed = menuSheet.getRange("AB2").getValue()
var index = inventoryData.findIndex(row => row[columnIndex] === matchText)
var rowNumber = index +1
var kg1 = inventoryLots.getRange(rowNumber,2).getValue();
var lot1 = inventoryLots.getRange(rowNumber,3).getValue();
var bb1 = inventoryLots.getRange(rowNumber,4).getValue();
var kg2 = inventoryLots.getRange(rowNumber,5).getValue();
var lot2 = inventoryLots.getRange(rowNumber,6).getValue();
var bb2 = inventoryLots.getRange(rowNumber,7).getValue();
var kg3 = inventoryLots.getRange(rowNumber,8).getValue();
var lot3 = inventoryLots.getRange(rowNumber,9).getValue();
var bb3 = inventoryLots.getRange(rowNumber,10).getValue();
Use array methods such as Array.filter() to get data more easily. Try this pattern to get started:
const ss = SpreadsheetApp.getActive();
const matchText = ss.getRange('Bag Label!D2').getValue();
const inventoryLots = ss.getSheetByName('Inventory & Lots');
const matchingData = inventoryLots.getDataRange().getValues()
.filter(row => row[0] === matchText);

Streamline Google Script for combining multiple CSV to avoid timeout

I am working on a sheet that combines 10 CSV files that are stored in a google folder into one google sheet. I have been able to run the code previously, but I am starting to run into a lot of time based errors. I am hoping that someone can help streamline the following code. I know that I could run this in a loop, but I don't think that would be any faster.
//Sets Sheets to variable
var AUG = DriveApp.getFilesByName("Set1.csv").next();
var Sep1 = DriveApp.getFilesByName("Set2.csv").next();
var Sep2 = DriveApp.getFilesByName("Set3.csv").next();
var Oct1 = DriveApp.getFilesByName("Set4.csv").next();
var Oct2 = DriveApp.getFilesByName("Set5.csv").next();
var Nov1 = DriveApp.getFilesByName("Set6.csv").next();
var Nov2 = DriveApp.getFilesByName("Set7.csv").next();
var Dec1 = DriveApp.getFilesByName("Set8.csv").next();
var Dec2 = DriveApp.getFilesByName("Set9.csv").next();
var Dec3 = DriveApp.getFilesByName("Set10.csv").next();
//Parse String
var csvAUG = Utilities.parseCsv(AUG.getBlob().getDataAsString());
var csvNov1 = Utilities.parseCsv(Nov1.getBlob().getDataAsString());
var csvNov2 = Utilities.parseCsv(Nov2.getBlob().getDataAsString());
var csvOct1 = Utilities.parseCsv(Oct1.getBlob().getDataAsString());
var csvOct2 = Utilities.parseCsv(Oct2.getBlob().getDataAsString());
var csvSep1 = Utilities.parseCsv(Sep1.getBlob().getDataAsString());
var csvSep2 = Utilities.parseCsv(Sep2.getBlob().getDataAsString());
var csvDec1 = Utilities.parseCsv(Dec1.getBlob().getDataAsString());
var csvDec2 = Utilities.parseCsv(Dec2.getBlob().getDataAsString());
var csvDec3 = Utilities.parseCsv(Dec3.getBlob().getDataAsString());
//Determine Lengths
var rowset1 = csvAUG.length
var rowset2 = rowset1+csvSep1.length;
var rowset3 = rowset2+csvSep2.length;
var rowset4 = rowset3+csvOct1.length;
var rowset5 = rowset4+csvOct2.length;
var rowset6 = rowset5+csvNov1.length;
var rowset7 = rowset6+csvNov2.length;
var rowset8 = rowset7+csvDec1.length;
var rowset9 = rowset8+csvDec2.length;
var rowset10 = rowset9+csvDec3.length;
var colset = csvAUG[0].length;
//Start Combines CSV's for Scores
ss.setActiveSheet(ss.getSheetByName("Raw Scores"));
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clear();
sheet.getRange(1, 1, rowset1, colset).setValues(csvAUG);
sheet.getRange(1+rowset2, 1, csvSep1.length, colset).setValues(csvSep1);
sheet.getRange(1+rowset3, 1, csvSep2.length, colset).setValues(csvSep2);
sheet.getRange(1+rowset4, 1, csvOct1.length, colset).setValues(csvOct1);
sheet.getRange(1+rowset5, 1, csvOct2.length, colset).setValues(csvOct2);
sheet.getRange(1+rowset6, 1, csvNov1.length, colset).setValues(csvNov1);
sheet.getRange(1+rowset7, 1, csvNov2.length, colset).setValues(csvNov2);
sheet.getRange(1+rowset8, 1, csvDec1.length, colset).setValues(csvDec1);
sheet.getRange(1+rowset9, 1, csvDec2.length, colset).setValues(csvDec2);
sheet.getRange(1+rowset10, 1, csvDec3.length,colset).setValues(csvDec3);

If column has value do ______

How to search a column on a sheet for a value, and if the value is there continue code? I am trying to make an update system to check to see if their email is on a sheet. If their email is on a sheet then it will check if their system version is up to date. If the system is not to up to date it will then copy their data, delete their current sheet, create a copy from an example then put in their data. If the user does not have the system it will create one for them. It seems to continuously skip Checking their email.
My code uses URLs and IDs but I have taken them out for obvious reasons. Below is an example of the beginning of my code.
function readlog()
var user = Session.getEffectiveUser().getUsername();
var email = Session.getEffectiveUser().getEmail();
var ss = SpreadsheetApp.openByUrl(URL_);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet = sheet.getSheetByName('8th grade')
var active = sheet.getRange('8th grade!b3:b').getValues()
if (email == active) {
//do something
}
Here is a full version of my code:
function readlog(){
var user = Session.getEffectiveUser().getUsername();
var email = Session.getEffectiveUser().getEmail();
var timezone= "CST";
var date = Utilities.formatDate(new Date(),timezone, "E MMM dd,yyyy HH:mm:ss");
var ss = SpreadsheetApp.openByUrl(URL_);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var sheet = sheet.getSheetByName('8th grade')
var active = sheet.getRange('8th grade!b3:b').getValues()
if (email == active) {
var container = DriveApp.getFoldersByName('Reading Log')
var fid = DriveApp.getFoldersByName('Reading Log').getId()
var version = sheet.getRange('8th grade!a1')
var update = container.getDescription();
if (update == version) {
var ui = SpreadsheetApp.getUi();
var response = ui.alert('You already have a reading log, and you have the most recent update!', ui.ButtonSet.OK);
} else {
var contents = container.getFiles();
var files = DriveApp.getFolderById(fid).searchFiles(
'title contains "Reading log"');
while (files.hasNext()) {
var file = files.next();
var logtoupdate = file.getUrl;
}
var ss = SpreadsheetApp.openByUrl(logtoupdate);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var logrange = sheet.getRange('8th Grade!e5:o').getValues()
SpreadsheetApp.getActiveSpreadsheet().deleteActiveSheet();
var master = DriveApp.getFileById(URL_);
var read = master.makeCopy("Reading Log",container);
var target = read.getRange('8th Grade e5:o').setValues(logrange);
var range = sheet.getRange("A1:B2");
range.setValues([[50, 100]]);
var ss = SpreadsheetApp.openByUrl(URL_);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet()
}
} else {
var ss = SpreadsheetApp.openByUrl(URL_);
SpreadsheetApp.setActiveSpreadsheet(ss);
var sheet = SpreadsheetApp.getActiveSpreadsheet()
var targetFolder = DriveApp.createFolder("Reading Log");
var eighth = DriveApp.getFileById(URL_);
var share = eighth.makeCopy("(Name): 8th Grade Reading Log",targetFolder);
var master = DriveApp.getFileById(URL_);
var read = master.makeCopy("Reading Log",targetFolder);
var folder = sheet.getRange('8th grade!a1');
targetFolder.setDescription(folder);
var idsheet = read.getUrl();
var idshare = share.getUrl();
var idfolder = targetFolder.getUrl()
sheet.appendRow([user,email,date,idfolder,idsheet,idshare]);
var ui = SpreadsheetApp.getUi();
var response = ui.alert('Your Reading log is created. There is now a folder in your google drive called Reading log. Have Fun Reading!', ui.ButtonSet.OK);
}
}
Short answer
Instead of email == active use active.join('|').split('|').indexOf(email)
Explanation
getValues() return a two dimensional array.
join('|') convert this array into an string using | as separator.
split('|') convert the above string into an (one dimension) array.
indexOf(email) returns the index of the email value on the above array. If the email value is not found, -1 is returned.
On a comparison -1 is parsed as false.

Copy value and format from a sheet to a new google Spreadsheet document?

I need to copy a sheet on google SpreadSheet to another SpreadSheet document.
I´ve done my research, and I found two methods that do this, however both have problems that I don´t know how to fix.
The first method copies the sheet with format, but it keeps the referenced cells, so I get a reference error in the new document (#ref). I need a function that copies the format and the values (not references).
function copySheet() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getSheets()[0];
var destination = SpreadsheetApp.openById("15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ");
sheet.copyTo(destination);
}
This second method copies the values without references, however it copies only values, without format.
function copySheetValues()
{
var source = SpreadsheetApp.getActiveSheet();
var sourcename = source.getSheetName();
var sourceDataRange = source.getDataRange();
var sourceSheetValues = sourceDataRange.getValues();
var sourceRows = sourceDataRange.getNumRows();
var sourceColumns = sourceDataRange.getNumColumns();
var destination = SpreadsheetApp.openById('15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ');
destination.insertSheet(sourcename, 0);
destination.getDataRange().offset(0, 0, sourceRows, sourceColumns).setValues(sourceSheetValues);
}
How do I write a function that keeps the format and copies the values?
Since you seem to know how to get and set values using the whole data range, just use the other methods to get and set all the other parameters.
The script editor autocomplete is a great help in this case to try not to forget one !
I hope the list is complete, it is a bit of a pain to write though !.
code below, if one of them is not useful to you just delete it (in both directions (set and get).
function copySheetValues(){
var source = SpreadsheetApp.getActiveSheet();
var sourcename = source.getSheetName();
var sValues = source.getDataRange().getValues();
var sBG = source.getDataRange().getBackgrounds();
var sFC = source.getDataRange().getFontColors();
var sFF = source.getDataRange().getFontFamilies();
var sFL = source.getDataRange().getFontLines();
var sFFa = source.getDataRange().getFontFamilies();
var sFSz = source.getDataRange().getFontSizes();
var sFSt = source.getDataRange().getFontStyles();
var sFW = source.getDataRange().getFontWeights();
var sHA = source.getDataRange().getHorizontalAlignments();
var sVA = source.getDataRange().getVerticalAlignments();
var sNF = source.getDataRange().getNumberFormats();
var sWR = source.getDataRange().getWraps();
var destination = SpreadsheetApp.openById('15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ');
var destinationSheet = destination.insertSheet(sourcename, 0);
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues)
.setBackgrounds(sBG)
.setFontColors(sFC)
.setFontFamilies(sFF)
.setFontLines(sFL)
.setFontFamilies(sFFa)
.setFontSizes(sFSz)
.setFontStyles(sFSt)
.setFontWeights(sFW)
.setHorizontalAlignments(sHA)
.setVerticalAlignments(sVA)
.setNumberFormats(sNF)
.setWraps(sWR);
}
Edit :
Bryan's answer and your comment made me think of another solution, much more simple and that handles merged cells as well. Here is the code :
function copySheetValuesV2(){
var source = SpreadsheetApp.getActiveSheet();
var sourceName = source.getSheetName();
var sValues = source.getDataRange().getValues();
var destination = SpreadsheetApp.openById('15ucPbZrIYXZAOCYVdpK6OA0oyQT1NcsmuiJmDRfdpHQ');
source.copyTo(destination)
var destinationSheet = destination.getSheetByName('Copy of '+sourceName)
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues);// overwrite all formulas that the copyTo preserved
}
In both script be sure that the destination sheet name does not already exist. I didn't handle that case although it is quite easy to do with a try/catch structure.
Another route to try that I think Serge was alluding to here.
function myFunction() {
var source = SpreadsheetApp.openById('SOURCE_ID');
var sourceSheet = source.getSheetByName('Sheet1');
var sourceRange = sourceSheet.getDataRange();
var sourceValues = sourceRange.getValues();
var tempSheet = source.getSheetByName('temp');
var tempRange = tempSheet.getRange('A1');
var destination = SpreadsheetApp.openById('DEST_ID');
sourceRange.copyTo(tempRange); // paste all formats?, broken references
tempRange.offset(0, 0, sourceValues.length, sourceValues[0].length)
.setValues(sourceValues); // paste all values (over broken refs)
tempSheet.copyTo(destination); // now copy temp sheet to another ss
}
This is a variation upon Sergei's answer.
This script will copy all visible sheets and export them in to a new spreadsheet with " Final" appended to the document title.
function copySheetValuesV4(){
var sourceSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheets = sourceSpreadsheet.getSheets();
var destination = SpreadsheetApp.create(sourceSpreadsheet.getName()+' Final');
for (var i = 0; i < sourceSheets.length; i++){
var sourceSheet = sourceSheets[i];
if (!sourceSheet.isSheetHidden()) {
var sourceSheetName = sourceSheet.getSheetName();
var sValues = sourceSheet.getDataRange().getValues();
sourceSheet.copyTo(destination)
var destinationSheet = destination.getSheetByName('Copy of '+sourceSheetName).setName(sourceSheetName);
destinationSheet.getRange(1,1,sValues.length,sValues[0].length).setValues(sValues);// overwrite all formulas that the copyTo preserved */
}
destination.getSheetByName("sheet1").hideSheet() // Remove the default "sheet1" */
}
}