Make copy of Spreadsheet with content only - google-apps-script

How to make a copy of a google sheet with content only.
My problem is that there is a function that already allows you to do this on the ranges of a sheet with ({contentonly: true}). But it doesn't work if there is an importrange.
Is there a way to make a copy of a sheet of values only (even if there is an importange)?
May be something like this :
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var destFolder = DriveApp.getFoldersByName("Experiments").next();
var file = DriveApp.getFileById(spreadsheet.getId()).makeCopy("Saved Copy", destFolder);
var newSpreadsheet = SpreadsheetApp.open(file);
for(var i = 0; i < spreadsheet.getNumSheets(); i++){
newSpreadsheet.getSheets()[i].getDataRange().setValues(spreadsheet.getSheets()[i].getDataRange().getValues());
}
But it is not very efficient, if there are many cells.

Maybe the performance problem is caused by calling too many Spreadsheet Service methods (i.e. Spreadsheet.getSheets() is called two times inside a loop). Try the following:
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var destFolder = DriveApp.getFoldersByName("Experiments").next();
var file = DriveApp.getFileById(spreadsheet.getId()).makeCopy("Saved Copy", destFolder);
var newSpreadsheet = SpreadsheetApp.open(file);
var sheets = newSpreadsheet.getSheets(); // Call SpreadsheetApp.getSheets() only once per script execution
for(var i = 0; i < sheets.length; i++){
sheets[i].getDataRange().setValues(sheets[i].getDataRange().getValues());
}

Related

Is there a better way to make a copy of a spreadsheet with content only?

I've been trying to copy only the content (no equations such as =IMPORTRANGE) of a spreadsheet into a new spreadsheet. I have found a solution however I was wondering if there was an easier way to do this?
I ended up iterating through each sheet in the original spreadsheet, getting the data range of each sheet, getting those values, copying each sheet into the new spreadsheet with .copyTo, deleting the "Sheet1" created with the new spreadsheet, then iterating through the new spreadsheet and pasting the values to each new sheet in the spreadsheet.
function copySpreadsheetContent() {
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var sheetNums = ss1.getNumSheets();
var ssNew = SpreadsheetApp.create('Test Spreadsheet').getId();
var ss2 = SpreadsheetApp.openById(ssNew);
var ss2Nums = ss2.getNumSheets();
var sheetVals = [];
for(var i = 0; i < sheetNums; i++){
var sheet = ss1.getSheets()[i];
sheetVals[i] = sheet.getDataRange().getValues();
var newSheet = sheet.copyTo(ss2);
newSheet.setName(sheet.getName());
}
var sheet1 = ss2.getSheetByName("Sheet1");
ss2.deleteSheet(sheet1);
for(var j = 0; j <= ss2Nums; j++){
var ss2Sheet = ss2.getSheets()[j];
ss2Sheet.getDataRange().setValues(sheetVals[j]);
}
}
This provides the desired results as far as I can tell, however it just seems like a really roundabout way of doing things and I was hoping someone might be able to point me to a more efficient or straightforward method.
Thanks for the help
My coworker ended up finding a better way to do this with a single for loop and the ability to send it to a folder in your drive
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var destFolder = DriveApp.getFoldersByName("Experiments").next();
var file = DriveApp.getFileById(spreadsheet.getId()).makeCopy("Saved Copy", destFolder);
var newSpreadsheet = SpreadsheetApp.open(file);
for(var i = 0; i < spreadsheet.getNumSheets(); i++){
newSpreadsheet.getSheets()[i].getDataRange().setValues(spreadsheet.getSheets()[i].getDataRange().getValues());
}

How can I make my script save the copy to a specific folder?

I am using the below script to make a copy of my google worksheet (values and formatting only). However, this script is placing the new file in my main google drive and I want the file to be saved to an archive folder. How can I edit my script to do this?
function copySheetValuesV4(){
var sourceSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheets = sourceSpreadsheet.getSheets();
var destination = SpreadsheetApp.create('03_'+sourceSpreadsheet.getName()+' _December 2017');
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" */
}
}
Use DriveApp.getFolderById(folder_id).addFile(DriveApp.getFileById(destination.getId())). This gets the spreadsheet ID and then adds the spreadsheet to a folder.

google sheets script conditionally move row to another spreadsheet

I am new to this and I am having some trouble trying to figure this out. I have a spreadsheet that collects data from a google form. I am trying to find a way to move that data based on a column answer to a different google sheet. (Not a sheet in the same document but a different document all together). It seems like there is some information about moving to a different tab in the same document, but not a different document.
I will first say that I tried just an IMPORTRANGE function, but that only mirrors the data, and does not let you update or change cells.
Here is what I have been able to piece together so far, but I may be way off.
I have a trigger that would run every hour.
function myFunction() {
var ss = SpreadsheetApp.openById('1U0I9SkbGkHgm-vRkwf2Ppc_yxlqrVlg2t8yKRy3sYuI');
var sheetOrg = ss.getSheetByName("Form Responses 1");
var value1ToWatch = "ANDERSON";
var value2ToWatch = "BARNES";
var sheetNameToMoveTheRowTo = "Sheet1"; //sheet has same name for each target openByID(" *url key* ")
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ts1 =SpreadsheetApp.openById("1PxV1PQrMdu_2aSru4dpan8cUgHYdlYPUp5anyzjMAms");
sheet1in = ts1.getSheetByName("Sheet1");
var ts2 = SpreadsheetApp.openById("1BYyQZNiXc2QqsyqWs7uazjl5B6mfFYM1xj3u8gWyYOQ");
sheet1in = ts2.getSheetByName("Sheet1");
arr = [],
values = sheetOrg.getDataRange().getValues(),
i = values.length;
while (--i) {
if (value1ToWatch.indexOf(values[i][1]) > -1) {
arr.unshift(values[i])
sheetOrg.deleteRow(i + 1)
sheet1in.getRange(sheet1in.getLastRow()+1, 1, arr.length,
arr[0].length).setValues(arr);
};
if (value2ToWatch.indexOf(values[i][1]) > -1) {
arr.unshift(values[i])
sheetOrg.deleteRow(i + 1)
sheet2in.getRange(sheet2in.getLastRow()+1, 1, arr.length,
arr[0].length).setValues(arr);
};
}
}
The sheet google forms dumps the information into is "Form Responses 1".
Column B is the cells I want to get the values from. (There are a total of 9 different values that it can be like "ANDERSON", "BARNES", "SMITH", etc).
For sheetNameToMoveTheRowTo is "Sheet1" - that may be confusing and I may need to change that, but for example
ts1 =SpreadsheetApp.openById("1PxV1PQrMdu_2aSru4dpan8cUgHYdlYPUp5anyzjMAms") the sheet name that I want the information moved to is "Sheet1".
ts2 = SpreadsheetApp.openById("1BYyQZNiXc2QqsyqWs7uazjl5B6mfFYM1xj3u8gWyYOQ") the sheet name is also "Sheet1" but in a different document.
I think if I were able to get the "ANDERSON" one to work, then I can just add additional variables for each possible response, and just copy and paste additional "IF" statements, just changing the valueToWatch and targetSheet values. <= if that is not correct please let me know
I have tried to both debug, and run the script above but nothing happens. There are no errors reported on the debug, but it is not moving any information over.
Any idea what I am doing wrong?
// UPDATE I got this to work. I have updated the code listed with what worked for me.
I think that copyTo() method will not work like you mentioned, it operates on same SpreadSheet. I'm sending you example with looping on source sheet data and then setting the target sheet values with it.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var allrange = ss.getActiveRange();
var range = sheet.getRange("A1:A10");
var values = range.getValues();
var allvals = [];
for(var i = 0; i < values.length; i++) {
allvals.push( values[i] ) ;
}
var dataLength = allvals.length;
// alert data
var ui = SpreadsheetApp.getUi();
// ui.alert( JSON.stringify(allvals) )
// copy to new Google SpreadSheet
var newSheet = SpreadsheetApp.openById('1F79XkNPWm2cCWlB2JP3K4tAYRESKUgtHK4Pn2vbJEiI').getSheets()[0];
var tmp = "A1:A" + dataLength ;
var newRange = newSheet.getRange( tmp );
newRange.setValues( allvals );
}
Here's a simple example of moving data from one spreadsheet to another.
function movingDataToSS(){
var ss=SpreadsheetApp.getActive();
var dss=SpreadsheetApp.openById('ssId');
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var dsh=dss.getSheetByName('Sheet1');
var drg=dsh.getRange(1,1,rg.getHeight(),rg.getWidth()).setValues(vA);
}
If you interested in placing some conditions on your output by only getting output from odd rows and even columns.
function movingDataOddRowsAndEvenCols(){
var ss=SpreadsheetApp.getActive();
var dss=SpreadsheetApp.openById('ssId');
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var h=rg.getHeight();
var w=rg.getWidth();
var dsh=dss.getSheetByName('Sheet1');
for(var i=0;i<h;i++){
var out=[];
if(i%2==0){
for(var j=0;j<w;j++){
if(j%2==1){
out.push(vA[i][j]);
}
}
dsh.appendRow(out);
}
}
}

How can I use a Google Apps Script to add multiple Google Docs to a Google Drive folder?

I have a list of Google Document URLs (about 700 of them) and need to add them to a Google Folder so that they are all in one space because currently they are owned by hundreds of different users.
I've seen a few postings on how to do the inverse of this: Generate a list of URLs from the contents of a folder. This has been helpful, but it seems this task is much more difficult.
This is what I've tried, and it doesn't seem to be working:
var doc = DocumentApp.openById('1sQGds0kyeO66ZiMiJlsKkHPcqjySPy5q0dWShc2irts'),
docFile = DriveApp.getFileById( doc.getId() );
DriveApp.getFolderById('0B7yp85g7j5ZHbVlEUmNGX2w0M1k').addFile( docFile );
DriveApp.getRootFolder().removeFile(docFile);
it doesn't error check and may timeout... but it is a start.
You would add the fileIds in Column A.
function makeCopyFromId() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 700; // Last row to process.
var dataRange = sheet.getRange(startRow, 1, numRows, 5)
var data = dataRange.getValues();
var destFolder = DriveApp.getFolderById("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
for (i in data) {
var row = data[i];
var ssId = row[0];
Logger.log(ssId); // check the log to see if they all complete-
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(ssId).makeCopy("",destFolder)) //copies each file.
}}

Change copyDown() Script to operate on just one Sheet

In Google Sheets I have a sheet with Form Responses, and to the right of the form columns I have columns with formulas that use form data for functions.
At the start I had the formulas extended down the rows so they worked on new form submissions, but found that new form submissions would clear the row out :(.
Instead of manually extending formulas down after each submission I installed Andrew Stillman's copyDown() script; what it does is copies down the formulas after scripts are submitted.
Now the problem I'm having is that the script works when run manually, but when I set to trigger on form submits it copies the said formula on that sheet and on all other sheets in the spreadsheet. I Do Not Want that side-effect, as it messes the whole spreadsheet up. :((
What I thought to do is edit script so it only works on the one Form Response sheet, not all sheets. But I don't know how to do that.
The name of the sheet I want it to run on is "Requests", and the gid=8.
How do I edit this script to only work for that one sheet?
To get code to run on just a particular sheet use the .getSheetByName() method. For example:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var reqSh = ss.getSheetByName('Requests');
There is another way that might be easier. You could try keeping one sheet purely for form submissions and use an arrayformula in a second sheet to copy any values from the first sheet to the same range in the second.
=ARRAYFORMULA('Requests'!A1:H) would copy columns A to H.
I had the same problem as you and this was the solution. I placed my formulas in the second sheet in the columns to the right of the range and copied them down in the normal way. The formulas referred to the copied range in the second sheet. It worked a treat.
I didn't come up with the idea myself - I'm sure it was suggested by someone on the Google spreadsheet forum. I should give you a link to the post but I just looked and I can't find it.
In your code you have (comments in code)
var sheets = ss.getSheets() [8]; // you choose sheet [8]
var cellAddresses = new Object();
for (var i=0; i<sheets.length; i++) { // but you enter a for loop that adresses every sheet in turn...
var range = sheets[i].getDataRange();
You should simply suppress this loop and use only the sheet number you want to be proceeded ...
The simplest way could be to do it like this :
var i = 8
var sheets = ss.getSheets() [i];
var cellAddresses = new Object();
var range = sheets[i].getDataRange();
...
and at the end of the loop delete the } that fitted the for loop
EDIT : the new code should be like this :
function copydown() {
setCopyDownUid();
setCopyDownSid();
logCopyDown();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets() [8];
var cellAddresses = new Object();
var i=8
// for (var i=0; i<sheets.length; i++) {
var range = sheets[i].getDataRange();
var lastRow = range.getLastRow();
var values = range.getValues();
for (var j=0; j<values.length; j++) {
for (var k=0; k<values[j].length; k++) {
var test = values[j][k].toString();
var start = test.indexOf("copydown");
if (start == 0) {
start = start+10;
var end = test.length-2;
var length = end-start;
var value = test.substr(start, length);
var col = k+1;
var nextRow = j+2;
var numRows = lastRow-(nextRow-1);
if (numRows>0) {
var destRange = sheets[i].getRange(nextRow, col, numRows, 1);
destRange.clear();
var newLastRow = sheets[i].getDataRange().getLastRow();
var newNumRows = newLastRow-(nextRow-1);
var newDestRange = sheets[i].getRange(nextRow, col, newNumRows, 1);
var cell = sheets[i].getRange(nextRow-1, col);
cell.setFormula(value);
cell.copyTo(newDestRange);
}
var cellAddress = cell.getA1Notation();
cellAddresses[cellAddress] = test;
}
}
}
Utilities.sleep(500);
resetCellValues(cellAddresses, sheets[i]);
}
//}