Copying values and formulas from one spreadsheet to another - google-apps-script

I have a template spreadsheet and multiple copies of it. I need to be able to update the template spreadsheet's sheets (be it values or formulas) and quickly reflect theses changes across all the spreadsheet copies.
The obstables are:
The copy method does not work in this case because it only works within the same spreadsheet;
Copying an entire sheet also does not work because it breaks the charts (adding a new sheet, removing old one, renaming new sheet);
I tried to use getValues and getFormulas and then use the following code to have one complement the other:
var combined = []
for (cell in templateValues) {
var row = [];
if (templateValues[cell] == '') {
row.push(templateFormulas[cell])
} else {
row.push(templateValues[cell])
}
combined.push(row);
}
Logger.log(combined)
and then using
var targetRange = targetSheets[sheet].getRange(1, 1, combined.length, combined[0].length);
targetRange.setValues(combined);
to paste the values. That did not work (values weren't pasted in the right place nor were formulas).
Any ideas?
EDIT: Including some sample spreadsheets for clarity.
Source Spreadsheet and Target Spreadsheet.
Again, the point is that I can copy everything in the "SameSheet" sheet of the Source Spreadsheet to the "SameSheet" sheet of the Target Spreadsheet (in the actual use case it is a Drive folder with multiple target spreadsheets).

Related

Script to copy, transpose then paste values into another sheet, and then when next run to do the same, into the next available rows

I am trying to write a script that will move data from one sheet to another and simultaneously transpose it. I need to use the same script on the same Input Range several times (with different data), so it needs to paste each set of data in the next available set of rows in the destination sheet.
I have looked extensively on the site for solutions, but I have only been able to find solutions for each of these functions separately. (Copy and Paste, Transpose, Only paste in next empty row, and date Timestamp)
The only code I have been working on if from the first of those, and is as follows;
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange("Import!E4:I41");
var destSheet = ss.getSheetByName("Database!E3:AP7");
destSheet.appendRow(source.getValues()[0]);
var destination = destSheet.getRange(destSheet.getLastRow(), 1); // Added
source.copyTo(destination, SpreadsheetApp.CopyPasteType.PASTE_VALUES) // Added
}
Happy to learn more and have any feedback from people who know better.
Example Sheet, with Ideal Solution

How to have a reference to a sheet bound to the name instead of the sheet

I'm making a spreadsheet to format the responses of a google form. However, this form will be given every week; ideally, I would like to import the form responses into this spreadsheet, have the formatted data sheet now use this new responses sheet instead of the older one, without having to update the formulae in the data sheet. But if I try to do this by renaming the new data sheet to what the old one was called, it keeps the old sheet reference and updates its name in all the formulae.
I haven't found any solutions from a few google searches. Is there an easy way to get around this?
EDIT: here is an example spreadsheet. Ideally, I want the data in 'Formatting Sheet' to be retrieved from 'New Sheet' instead of old sheet. However, I don't want to have to change all of the formulae in 'Formatting Sheet' to reflect this, as this will be a transition I do regularly. Unfortunately renaming the sheets preserves the reference.
You want to use the values at the sheet Formatting Sheet by replacing the values in the sheet Old Sheet with new values in the sheet New Sheet.
In your current issue, even when the sheet name is changed, the values cannot be updated.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
In your case, even when the sheet name is changed, the sheet ID is not changed. By this, the formula uses old values. I think that the reason of your issue is this. In this answer, in order to achieve your goal, Google Apps Script is used.
Flow:
The flow of the sample script is as follows.
Retrieve the sheet object of New Sheet and Old Sheet, which are the source sheet and destination sheet, respectively.
Backup Old Sheet.
In you don't want to backup it, please remove destinationSheet.copyTo(ss).setName(destinationSheet.getName() + "_backup_" + new Date().toISOString());.
Copy the values from New Sheet to Old Sheet. By this, the values are replaced. And at Formatting Sheet, the new values are used.
Sample script:
Please copy and paste the following sample script to the script editor of your shared Spreadsheet. And run myFunction().
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName("New Sheet");
var destinationSheet = ss.getSheetByName("Old Sheet");
// Backup "Old Sheet".
destinationSheet.copyTo(ss).setName(destinationSheet.getName() + "_backup_" + new Date().toISOString());
// Put values from "New Sheet" to "Old Sheet"
sourceSheet.getDataRange().copyTo(destinationSheet.getRange(1, 1));
}
When you run the script of myFunction(), you can see the result calculated by new values at the sheet of Formatting Sheet.
References:
copyTo() in Class Sheet
copyTo() in Class Range

How to create Google Scripts loop to activate and copy data from each tab in the workbook

I have a Spreadsheet that has X number of sheets (the number of sheets will change constantly). The format of the data in each sheet is the same. I want to create a macro to activate each sheet in the Spreadsheet and pull data from specific cells into a new sheet (essentially I'm consolidating info from each sheet in one place). I see how to activate a sheet using getSheetByName(), but the name and number of sheets will change regularly. I was hoping to create a loop that does the following:
Activate the first sheet.
Copy data from a few cells in that sheet to a "Dashboard" sheet.
Activate the next sheet.
Copy data from a few cells in that sheet to a "Dashboard" sheet.
Repeat until all sheets have been reviewed.
I can use the following code to activate the next sheet, but how do I make a loop that stops after the last sheet?
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A2').activate();
var nextSheetIndex = spreadsheet.getActiveSheet().getIndex() + 1;
if (nextSheetIndex > spreadsheet.getSheets().length) { nextSheetIndex = 1; }
spreadsheet.setActiveSheet(spreadsheet.getSheets()[nextSheetIndex - 1], true);
spreadsheet.getRange('A2').activate();
nextSheetIndex = spreadsheet.getActiveSheet().getIndex() + 1;
Any tips would be greatly appreciated!
First of all, you don't need to activate Sheet to perform changes. Since you want to iterate over each Sheet in a Spreadsheet, use the getSheets() method to retrieve an Array of Sheet instances.
Then, iterate over each Sheet with a loop of your liking (for,for...in,forEach(),etc) and, during each iteration of the loop, access the Range value you want to pull data from via getRange(yourRangeReference).getValue() and copy it to the destination Sheet.
If you need to check and account for number of sheets changing dynamically, while you are iterating over them, getNumSheets() method on each iteration step and, if its result is greater than initial, access and then push() this sheet into the Array.
Useful links
MDN documentation on for loop (the simplest one);
SpreadsheetApp reference for Spreadsheet service;
Developer guide on extending Google Sheets;

copyTo range does not copy drawings?

When I use copyTo to copy an entire sheet, drawings get copied but I don't want to copy the entire sheet so I tried to use copyTo on a range but drawings do not get copied. Anyone know if this is expected behavior or a bug? For example if a drawing is in A4 ...
function test() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var test1 = ss.getSheetByName("test1");
var test2 = ss.getSheetByName("test2");
// this does not copy drawing to sheet test2
var rangeToCopy = test1.getRange(1,1,5,1);
rangeToCopy.copyTo(test2.getRange(1,1));
// this copies drawing to new sheet Copy of test1
test1.copyTo(ss);
}
I realize there are two copyTo's, one for sheets and one for ranges, just would have expected they both should copy drawings.
no, it doesnt copy drawings. a big part of it is that drawings do not sit on a given cell or range.
you can confirm this by inserting rows above the drawing. sometimes google shifts the drawing down and sometimes doesnt, so it's not tied to specific rows, at least not strictly.
you can also confirm that copying ranges manually with the web interface also doesnt copy the drawings.
one solution is to convert the drawing to an image and host it somewhere (like a google sites cabinet with public access) and use cell formula `=IMAGE("http://path.to.image.png")' which will get copied.
another way if you must use drawings, is to copy the entire sheet into a new sheet, then manually copy the ranges that you didnt want to overwrite from your destination sheet, then delete the original destination sheet and rename the new sheet with the destination name.

Google Spreadsheets with Form Vinculated copy

I'm trying to copy a spreadsheet with the responses of a form thought drive API.
https://developers.google.com/drive/v2/reference/files/copy
All files from my drive are working fine but only this spreadsheet that persist my form answers that create a duplicate form instead of only copying the spreadsheet itself.
You can try to reproduce the problem using the given Id. After copying you will notice that both spread sheet and form will be copied. This should not be a problem if I could erase the form but in the response of the copy procedure I don't get any advice about the form that is being copied together.
File id: 0Aqq-9JjR-lUydHRKVEJ2SThGMjJlVjVqczkyWlVCWUE
Please, help me. I'm desperate.
If you are only trying to copy the spreadsheet of the form, try this:
var fromSheet = ***whatever***;//this is the sheet attached to your form
var toSheet = ***whatever***;//this will be the sheet that you are copying to
var range = **whatever***;//this is the range you are copying over. If you are using dynamic ranges (ie varying number of rows), you may want to **getDataRange()** and **getLastRow** to build a more flexible range
function myCopyCat(){
myValues = fromSheet.getRange(range).getValues();//'copies' all of your data within range from fromSheet to an array
toSheet.getRange(range).setValues(myValues);//'pastes' all of your data into cells on toSheet
}