I have used a variation of this: How to copy format and values, not formulas, when creating a spreadsheet backup in Google Apps Script?
code here:
function copySheet() {
var spreadsheetId = "1O6D59wAwzq45fHHPrlZea_cpZsVdlTuct0YgJRD3iyw"; // Please set the source Spreadsheet ID.
var destFolderId = "18L8k7jtldUQTonp5VO5ZBFd6j_AoC0bj"; // Please set the destination folder ID.
// Copy each sheet in the source Spreadsheet by removing the formulas as the temporal sheets.
var ss = SpreadsheetApp.openById(spreadsheetId);
var tempSheets = ss.getSheets().map(function(sheet) {
var dstSheet = sheet.copyTo(ss).setName(sheet.getSheetName() + "_temp");
var src = dstSheet.getDataRange();
src.copyTo(src, {contentsOnly: false});
return dstSheet;
});
// Copy the source Spreadsheet.
var timeZone = Session.getScriptTimeZone();
date = Utilities.formatDate(new Date(), timeZone, "YYMMdd");
var destination = ss.copy(ss.getName() + " - " + date);
// Delete the temporal sheets in the source Spreadsheet.
tempSheets.forEach(function(sheet) {ss.deleteSheet(sheet)});
// Delete the original sheets from the copied Spreadsheet and rename the copied sheets.
destination.getSheets().forEach(function(sheet) {
var sheetName = sheet.getSheetName();
if (sheetName.indexOf("_temp") == -1) {
destination.deleteSheet(sheet);
} else {
sheet.setName(sheetName.slice(0, -5));
}
});
// Move file to the destination folder.
var file = DriveApp.getFileById(destination.getId());
DriveApp.getFolderById(destFolderId).addFile(file);
file.getParents().next().removeFile(file);
}
function searchReplace() {
var FILE = SpreadsheetApp.openById("1vb3lv7boclruNyy116CN3oZXeqjUpPl5oFDSakEclDI");
var textFinder = FILE.createTextFinder('Raw').matchFormulaText(true);
textFinder.replaceAllWith('Raw');
}
To copy an entire sheet WITH formulas. The problem I have found is that the formulas referencing other sheets/tabs break with "Unresolved Sheet Name" error, even though the sheets do exist.
I have found a workaround here: https://support.google.com/docs/thread/25074318/unresolved-sheet-name-workaround-when-copying-or-renaming-tabs?hl=en
and am hoping to be able to search and replace within the new copied sheet to replace the word "Raw" within the formulas with "Raw" which will fix the broken formulas, all from the original script from the sheet being duplicated.
I hope this makes sense, I'd love to hear any suggestions or workarounds...
Thanks
If you are looking for an apps-script based solution, I answered a similar question here. I also wrote a short tutorial explaining the script. But that one was about replacing text.
You are looking to find-and-replace inside the formula.
To do that you need to tweak my script as follows:
var textFinder = activeSheet.createTextFinder('Raw').matchFormulaText(true);
This will look for the text Raw inside the formulas on the sheet.
To replace it with Cooked, the next line of the script is:
textFinder.replaceAllWith('Cooked');
Please ref my previous answer and tutorial for more.
Related
im new to this and have been looking every where how to do this:
Create new Google Spread Sheet.
Open new Google Spread Sheet.
Add code to new Google Spread Sheet.
Ive seen this code, but dont really understand it much. Can somebody explain or help me with this task?
var files = DriveApp.searchFiles(
'starred = true and mimeType = "' + MimeType.GOOGLE_SHEETS + '"');
while (files.hasNext()) {
var spreadsheet = SpreadsheetApp.open(files.next());
var sheet = spreadsheet.getSheets()[0];
Logger.log(sheet.getName());
Would duplicating a blank spreadsheet that already has App Script code attached to it work in your situation?
Steps Needed:
Create a blank Spreadsheet.
Add your code to the blank Spreadsheet.
Use the following code to make a copy of the blank spreadsheet. The App Script file will also be on the newly copied file.
To make a copy of the blank Spreadsheet, use this:
function copySpreadsheet() {
var templateSpreadsheetID = [Enter the Spreadsheet ID]
var newSheetName = [Enter the name you want the copied Spreadsheet to be]
var newSheet = SpreadsheetApp.openById(templateSpreadsheetID).copy(newSheetName)
console.log(newSheet.getUrl())
}
Notes:
You'll need to replace [Enter the Spreadsheet ID] with the Spreadsheet ID from the blank sheet you created in Step 1
You'll need to replace [Enter the name you want the copied Spreadsheet to be] with what ever name the new copied spreadsheet should be. It's optional, so you could remove it.
If you'd like to do further actions to the spreadsheet after it has been duplicated, you can use the newSheet variable to run your sheet actions
Can somebody explain or help me with this task?
The code you shared is a script that extract the first sheet name of each starred Spreadsheet.
//Returns all the starred files that are a Google Sheet file type:
var files = DriveApp.searchFiles('starred = true and mimeType = "' + MimeType.GOOGLE_SHEETS + '"');
//Loops through all of the files that were returned:
while (files.hasNext()) {
//Opens the current sheet from the loop
var spreadsheet = SpreadsheetApp.open(files.next());
//Returns the first sheet from the spreadsheet (position 0)
var sheet = spreadsheet.getSheets()[0];
//Logs the sheet name
Logger.log(sheet.getName());
}
I have a frozen backup script that works (below), but it times out due to the high number of rows and formulas. The script is to create a frozen backup with just the values (no formulas) of the entire spreadsheet (or some sheets). I'm trying to improve it by not copying the sheets with formulas to the new spreadsheet, but only copying the "frozen" copies of those sheets. Any help / guidance would be appreciated.
The script below works just fine with a spreadsheet that does not have too many rows and formulas. I've tried to modify it by using SpreadsheetApp.create instead of .copy to create a blank spreadsheet, and then trying to come up with how to use .forEach method with an if statement to identify _temp sheets and only copy them. I've been stuck for a while, hence this question.
The current script is:
function copyEntireSpreadsheet() {
var id = "ID"; // Please set the source Spreadsheet ID.
var ss = SpreadsheetApp.openById(id);
var srcSheets = ss.getSheets();
var tempSheets = srcSheets.map(function(sheet, i) {
var sheetName = sheet.getSheetName();
var dstSheet = sheet.copyTo(ss).setName(sheetName + "_temp");
var src = dstSheet.getDataRange();
src.copyTo(src, {contentsOnly: true});
return dstSheet;
});
var destination = ss.copy(ss.getName() + " - " + new Date().toLocaleString());
tempSheets.forEach(function(sheet) {ss.deleteSheet(sheet)});
var dstSheets = destination.getSheets();
dstSheets.forEach(function(sheet) {
var sheetName = sheet.getSheetName();
if (sheetName.indexOf("_temp") == -1) {
destination.deleteSheet(sheet);
} else {
sheet.setName(sheetName.slice(0, -5));
}
});
}
The script above times out because it takes too long in the new (copied) spreadsheet to process all cells with formulas, but there should be no need to copy them in the first place.
The script above works by:
Creating copies of all sheets and renaming with the addition of
"_temp".
Rewrites each "_temp" sheet over on itself with the parameter contentsOnly: true so that formulas become values.
Creates a copy of the entire spreadsheet.
Deletes the "_temp" sheets from the source spreadsheet.
Deletes the original sheets from the destination spreadsheet.
What I'd like to accomplish is:
Create copies of all sheets ("_temp") and rewrite on themselves to
get rid of formulas. (1 & 2 above)
Create a blank spreadsheet (new)
Copy only "_temp" sheets into the new spreadsheet (new)
Delete "_temp" sheets in source spreadsheet (4 above)
If I can modify it so that I can identify which sheets should be copied, that'd be even better, but a simple copy of all _temp sheets will also do the job.
Thanks in advance for any help!
Final Script
#Tanaike's answer was quick and simple - worked perfectly! Added .slice to remove "_temp" text from the new copied sheets. Here's the final script for anyone looking for a similar script:
function copyEntireSpreadsheetTest() {
var id = "ID"; // Please set the source Spreadsheet ID.
var ss = SpreadsheetApp.openById(id);
var srcSheets = ss.getSheets();
var tempSheets = srcSheets.map(function(sheet, i) {
var sheetName = sheet.getSheetName();
var dstSheet = sheet.copyTo(ss).setName(sheetName + "_temp");
var src = dstSheet.getDataRange();
src.copyTo(src, {contentsOnly: true});
return dstSheet;
});
var destination = SpreadsheetApp.create(ss.getName() + " - " + new Date().toLocaleString());
tempSheets.forEach(function(sheet) {
sheet.copyTo(destination).setName(sheet.getSheetName().slice(0,-5));
ss.deleteSheet(sheet);
});
destination.deleteSheet(destination.getSheets()[0]);
}
You want to achieve the following flow by modifying your script.
Create copies of all sheets ("_temp") and rewrite on themselves to get rid of formulas. (1 & 2 above)
Create a blank spreadsheet (new)
Copy only "_temp" sheets into the new spreadsheet (new)
Delete "_temp" sheets in source spreadsheet (4 above)
If my understanding is correct, how about this modification?
From:
var destination = ss.copy(ss.getName() + " - " + new Date().toLocaleString());
tempSheets.forEach(function(sheet) {ss.deleteSheet(sheet)});
var dstSheets = destination.getSheets();
dstSheets.forEach(function(sheet) {
var sheetName = sheet.getSheetName();
if (sheetName.indexOf("_temp") == -1) {
destination.deleteSheet(sheet);
} else {
sheet.setName(sheetName.slice(0, -5));
}
});
To:
var destination = SpreadsheetApp.create(ss.getName() + " - " + new Date().toLocaleString());
tempSheets.forEach(function(sheet) {
sheet.copyTo(destination).setName(sheet.getSheetName());
ss.deleteSheet(sheet);
});
destination.deleteSheet(destination.getSheets()[0]);
Reference:
copyTo(spreadsheet)
If I misunderstood your question and this was not the result you want, I apologize.
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.
I am new in google apps script. I need help for creating new spreadsheet by using existing spreadsheet and copy and sort the data into newly created spreadsheet using google apps script. Can anyone help me?
this does the trick:
function copySpreadSheet(newSpreadSheetName) {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var data = sheet.getSheetValues(1, 1, 1000, 26);
var newSheet = SpreadsheetApp.create(newSpreadSheetName)
newSheet.getSheetByName("Sheet1")
.getRange(1,1,1000,26).setValues(data);
}
function main() {
copySpreadSheet("some_Spreadsheet");
}
After executing main, you can find the new spreadsheet in your drive file list. If you want to change the range of the data that should be copied, adjust the getSheetValues() method like this: getSheetValues(startRow, startColumn, numRows, numColumns). Don't forget to do the same for the getRange method a few lines below, otherwise you will get an error.
You can use this simpler code:
function copySpreadSheet() {
var s = SpreadsheetApp.openById("id");
var destination = DriveApp.getFolderById("idOfFolder");
DriveApp.getFileById("id_ofFile").makeCopy("New name", destination);
}
This will create a copy of your file in a new destination.
The SpreadsheetApp#spreadsheet class has a method copy:
var wb = SpreadsheetApp.getActiveSpreadsheet();
var new = wb.copy("Copy of " + wb.getName());
This copy method copies the current spreadsheet and returns a reference to the new one, so additional tasks (such as removing unneeded sheets, formatting ranges, adding additional values, etc.) can be performed.
As a caveat, I am very new to Google Apps scripting. I appreciate any assistance that can be provided.
I am trying to copy the contents of a sheet into a new document. This code works without any problem:
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var projectname = SpreadsheetApp.getActiveSpreadsheet();
sheet = originalSpreadsheet.getActiveSheet();
sheet.copyTo(newSpreadsheet);
However, this copies over the formulas from the current sheet - I am trying to copy the values only, as the formulas reference data on other sheets in the original document.
My attempt to do this is as follows:
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var projectname = SpreadsheetApp.getActiveSpreadsheet();
sheet = originalSpreadsheet.getActiveSheet();
sheet.copyTo(newSpreadsheet, {contentsOnly:true})
However, this generates the following error: Cannot find method (class)copyTo($Proxy914,object).
I am unsure what I am doing wrong. Any assistance would be appreciated. Thanks in advance!
There are actually 2 copyTo, one applies to sheet and the other applies to Range
According to the documentation (see links above), the second one has optional argument to copy values only while the first has not.
What I guess you could do is use the Range.copyTo() to copy the whole sheet range to a temporary sheet (in the same spreadsheet) and then copy that temporary sheet to the other spreadsheet and finally delete the temporary sheet from the source spreadsheet.
Hoping it is clear enough ;-)
In the script gallery there is a script called spreadsheetFrozenBackup, through which a copy of a spreadsheet can be made.
The range.copyTo that Serge alludes to is used.
It is not a long script, so I reproduce it here for information:
// Make copy of current spreadsheet with backup name.
function spreadsheetFrozenBackup() {
// Get current spreadsheet.
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Name the backup spreadsheet with date.
var bssName = ss.getName() + " frozen at " + Utilities.formatDate(new Date(), "GMT", "yyyyMMdd HHmmss");
var bs = SpreadsheetApp.openById((DocsList.copy(DocsList.getFileById(ss.getId()), bssName)).getId());
// Make sure all the formulae have been evaluated...
SpreadsheetApp.flush();
// Get all the sheets in the spreadsheet
var bsl = bs.getSheets();
var pl = "";
for (var i = 0; i < bsl.length; i++) {
bsl[i].getDataRange().copyTo(bsl[i].getDataRange(), {contentsOnly:true});
pl = pl + " " + bsl[i].getName();
SpreadsheetApp.getActiveSpreadsheet().toast(pl, "Processed Sheets");
}
SpreadsheetApp.getActiveSpreadsheet().toast(bssName, "Frozen Backup");
}