Google Apps Script - copy to existing spreadsheet - google-apps-script

I'm attempting to use Google Apps Script copy() to 'publish' my master spreadsheet to an output spreadsheet, but getting multiple copies each time instead of it replacing the output file. Can anyone suggest a way to replace the contents of a destination spreadsheet so I can keep the same file-ID for the output and manually trigger a 'publish'. Have tried copyTo, but just makes multiple sheets instead.
The master spreadsheet is a staff roster that needs to be able to be worked on by multiple managers without staff seeing the live version. When the manager has finished updating, it can be pushed to staff.
Edit: Got it working
function publishRoster() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var sheet = source.getActiveSheet();
var updatedDateTime = sheet.getRange("A1");
var now = Utilities.formatDate(new Date(), "GMT+10:30", "dd/MM/yyyy H:mm")
updatedDateTime.setValue("Last Published " + now);
var sourceName = source.getSheetName();
// var sValues = source.getDataRange().getValues();
var destination = SpreadsheetApp.openById('my-destination-sheet-id-here');
var destinationSheet = destination.getSheetByName(sourceName);
if (destinationSheet == null ) { }
else { destination.deleteSheet(destinationSheet); }
sheet.copyTo(destination).setName(sourceName);
}

copyTo() creates a copy of existing sheet in the destination spreadsheet.
If you want to publish the changes from a specific sheet to specified destination sheet then you can copy the data from source sheet to destination sheet, instead of copying the whole sheet.[which will of course create new sheets each time you copy]
So the code to copy/publish data from master sheet to slave sheet goes as follows :
var SOURCEID = 'xxxxxxxxxxxxx'; //put your source spreadsheet id here
var SOURCESHEETNAME = 'XXXXX'; //put your source sheet name here
var DESTINATIONID = 'xxxxxxxxxxxxx'; //put your destination spreadsheet id here
var DESTINATIONSHEETNAME = 'XXXXX'; //put your destination sheet name here
var data = SpreadsheetApp.openById(SOURCEID).getSheetByName(SOURCESHEETNAME).getDataRange().getValues();
SpreadsheetApp.openById(DESTINATIONID).getSheetByName(DESTINATIONSHEETNAME).clear(); //This line is to clear the existing data in destination.
SpreadsheetApp.openById(DESTINATIONID).getSheetByName(DESTINATIONSHEETNAME).getRange(1, 1, data.length; data[0].length).setValues(data);
//data.length = no. of rows in source
//data[0].length = no. of columns in source
var now = Utilities.formatDate(new Date(), "GMT+10:30", "dd/MM/yyyy H:mm");
SpreadsheetApp.openById(DESTINATIONID).getSheetByName(DESTINATIONSHEETNAME).getRange("A1").setValue("Last Published " + now);
This is not a tested code, let me know if any issues arises, I'll be happy to help you.
Thanks

Related

Issue with duplicating a google sheet to a new file - only range wanted - not all

I have written a script that duplicates an entire google sheet to a new document and saves it in a folder when a button is pressed, however, I only want it to copy a specific range (A1:F52).
Every attempt I make at modifying the script to only have .getRange("A1:F52") throws an error that getrange is not a function, what am I doing wrong and how should it actually be?
This script functions perfectly as it is, but I just want it to only take the range across, any help would be greatly appreciated.
// SAVE INVOICE
function copyRowsWithCopyTo() {
// SET VALUES IN CELL
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A1:F60').activate();
spreadsheet.setCurrentCell(spreadsheet.getRange('F3'));
spreadsheet.getRange('A1:F60').copyTo(spreadsheet.getActiveRange(),
SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
//COPY CONTENTS TO INVOICE SHEET
let spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
let sourceSheet = spreadSheet.getSheetByName('DO NOT EDIT');
// SET SPREADSHEET MONTH
let targetSheet = spreadSheet.getSheetByName('JANUARY 2023');
let row = sourceSheet.getActiveRange().getRow();
let activeRow = sourceSheet.getRange( 2,1,1,20);
let last_row = targetSheet.getLastRow();
activeRow.copyTo(targetSheet.getRange('A'+(last_row+1)+':H'+(last_row+1)),{contentsOnly:true});
// REPLICATE INVOICE SHEET TO NEW DOCUMENT AND SAVE IN INVOICE FOLDER
var sheet = SpreadsheetApp.getActiveSheet(); // Get current active sheet.
//GET SHEET NAME
var sheet_name1 = sheet.getRange("F4").getValue(); // Get the value of cell F4, used to name the new spreadsheet.
var sheet_name2 = " - "
var sheet_name3 = sheet.getRange("A9").getValue(); // Get the value of cell A9, used to name the new spreadsheet.
var sheet_name = sheet_name1 + sheet_name2 + sheet_name3
var folder = DriveApp.getFolderById("1DVdganPrCfePk41kteKnXSqKmL4Pivu5");
// Get the ID of the folder where you will place a copy of the spreadsheet.
var newSS = SpreadsheetApp.create(sheet_name); // create new blank spreadsheet in a root folder
var asFile = DriveApp.getFileById(newSS.getId()); // get new spreadsheet as a file
folder.addFile(asFile); // add this file to destination folder
DriveApp.getRootFolder().removeFile(asFile); // remove a file from root folder
var copiedSheet = sheet.copyTo(newSS).getRange("A1:F52"); // copy active sheet to new spreadsheet
copiedSheet.setName(sheet_name); // rename copied sheet
newSS.deleteSheet(newSS.getSheetByName('Sheet1')); // remove "Sheet1" sheet which was created by default in new spreadsheet
// run Clear function
clear()
}
I am clearly mistyping the .getrange parameter as it throws an error, but I cannot work out what im doing wrong.

Apps Script - Creating a Spreadsheet then copy all the value and paste it in a different spreadsheet

I'm trying to to do the following tasks using Apps Script:
Create a new spreadsheet. The name will be "My spreadsheet" + Date of the day
Write a random value in the new spreadsheet
Copy the entire sheet (1st tab) from the new spreadsheet
Paste the value in another spreadsheet (in a specific sheet)
Here is the script I've written so far:
function copyPasteAllData() {
var date = Utilities.formatDate(new Date(), "GMT+7", "dd/MM/yyyy");
// get today's date
var ss = SpreadsheetApp.create("Existing Data - Apps Script - "+ date);
// create a new spreadsheet
var ssId = ss.getId();
// get ID of new spreadsheet
var existing = Sheets.Spreadsheets.Values.get('MyspreadsheetID', "Existing Data");
// get existing Spreadsheet + sheet location
var newSheet = Sheets.Spreadsheets.Values.get(ssId, "Sheet1");
// get new Spreadsheet + sheet location
ss.getRange('A1').setValue('1')
// setup a random value
var rangeAllData = newSheet.getRange(1, 1, newSheet.getMaxRows(), newSheet.getMaxColumns());
// copy the entire sheet from the
existing.rangeAllData.setValue()
}
I think the line below need to be changed but I'm not sure how to fix this.
I'm still quite a beginner with Apps Script and coding in general, apologies if it seems obvious.
var existing = Sheets.Spreadsheets.Values.get('MyspreadsheetID', "Existing Data");
var newSheet = Sheets.Spreadsheets.Values.get(ssId, "Sheet1");
Feel free to change anything in the script. Just note that I can only get the sheet ID and not the name
Thank you
Updated from the comment below:
In this case you can use the method getDataRange() to get the data from the new Sheet.
Then on the destination you can use the same range from the new sheet or use the one you want from the old sheet:
function copyPasteAllData() {
//getDate
var date = Utilities.formatDate(new Date(), "GMT+7", "dd/MM/yyyy");
//Create new sheet + set value
var newSheet = SpreadsheetApp.create("Existing Data - Apps Script - " + date);
newSheet.getRange('A1').setValue('this is new');
//get new sheet DataRange
var source = newSheet.getId();
var newSheetDataRange = SpreadsheetApp.openById(source).getSheets()[0].getDataRange().getA1Notation();
Logger.log(newSheetDataRange)
var newSheetValues = SpreadsheetApp.openById(source).getSheets()[0].getDataRange().getValues();
Logger.log(newSheetValues)
//copy the data to the old sheet
SpreadsheetApp.openById('OLD SHEET ID').getSheets()[0].getRange(newSheetDataRange).setValues(newSheetValues);
}

How can I get the responses directly form a Google Form and send then to a new spreadsheet?

I've been struggling to make a script that takes all the responses directly from a Google Form and sent it (or copy it) to a spreadsheet. I also want to send the spreadsheet to Google Drive after the copy is created (I already manage to do this part)
When I run the script it doesn't show any errors. The spreadsheet is created and stored in the given drive folder but the sheet is empty.
The is the script:
function getItemResponses() {
// Open a form by ID and create a new spreadsheet.
var form = FormApp.openById('1ohh3SYGm0F1wzIGeQenk6Vt-epeXY2UHgdYXtH5knWA');
//Prepare new name
var formattedDate = Utilities.formatDate(new Date(), "GMT", "dd-MM-yyyy' 'HH:mm:ss");
var name = form.getTitle() + " Copy " + formattedDate;
//Prepare file system objects
var oldfile = DriveApp.getFileById(form.getId());
destination = DriveApp.getFolderById("1u6HQQUWXKIkpakInbS9u6opWK10T91Ez");
//create new spreadsheet
var newSpreadsheet = SpreadsheetApp.create(name);
//Copy to newSpreadSheet
var form = FormApp.openById('1ohh3SYGm0F1wzIGeQenk6Vt-epeXY2UHgdYXtH5knWA'),getItemResponses,newSpreadsheet
//move to destination folder
var newFile = DriveApp.getFileById(newSpreadsheet.getId());
var parents = newFile.getParents();
while (parents.hasNext()) {
var parent = parents.next();
parent.removeFile(newFile); //remove from default folder
}
destination.addFile(newFile);
}
Thanks for your help in advance.
I believe your goal is as follows.
You want to retrieve all response values from the existing Google Form.
You want to put the retrieved values on the new Spreadsheet.
You want to put the new Spreadsheet in the specific folder.
Modification points:
In your script, the new Spreadsheet is created. But the response values are not put. I thought that this might be the reason for your issue.
In order to retrieve all response values from Google Form, I thought that this sample script might be able to be used. Ref
In order to move the created Spreadsheet to the specific folder, in this case, you can use moveTo.
When the above points are reflected in your script, it becomes as follows.
Modified script:
function getItemResponses() {
var form = FormApp.openById('1ohh3SYGm0F1wzIGeQenk6Vt-epeXY2UHgdYXtH5knWA');
var formattedDate = Utilities.formatDate(new Date(), "GMT", "dd-MM-yyyy' 'HH:mm:ss");
var name = form.getTitle() + " Copy " + formattedDate;
destination = DriveApp.getFolderById("1u6HQQUWXKIkpakInbS9u6opWK10T91Ez");
// Create new Spreadsheet.
var newSpreadsheet = SpreadsheetApp.create(name);
// Move the created Spreadsheet to the specific folder.
var newFile = DriveApp.getFileById(newSpreadsheet.getId());
newFile.moveTo(destination);
// Retrieve all response values from Google Form and put them to the created Spreadsheet.
var sheet = newSpreadsheet.getSheets()[0];
var titles = form.getItems().map(e => e.getTitle());
var formResponses = form.getResponses();
var values = formResponses.map(f => f.getItemResponses().reduce((o, i) => {
var r = i.getResponse();
return Object.assign(o, {[i.getItem().getTitle()]: Array.isArray(r) ? r.join(",") : r});
}, {})).map(o => titles.map(t => o[t] || ""));
values.unshift(titles);
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
}
When this script is run, a new Spreadsheet is created and it is moved to the specific folder, and all response values are retrieved from Google Form and they are put to the created Spreadsheet.
References:
moveTo(destination) of Class File
Related thread.
Storing all forms answers in one single file

Getting Service Time Out error on Google Scripts while copying data from one sheet to another?

I am using Google Script to copy content of one Google Sheet to another sheet. I am using the following code.
function copySheet()
{
// open the spreadsheets where the data will be stored
var sourceTable = SpreadsheetApp.openById("SheetID"); // source spreadsheet
var srcSheet = sourceTable.getSheetByName("RawData");
var targetTable = SpreadsheetApp.openById("SheetID"); // target spreadsheet
var tarSheet = targetTable.getSheetByName("Sheet3");
// get the last row in the source sheet
var lastRowSource = srcSheet.getLastRow();
var lastCol = "L";
//read the source into an array
var aSrc = srcSheet.getRange("A1:" + lastCol + lastRowSource).getValues();
//save src array to destination
tarSheet.getRange("A1:" + lastCol + lastRowSource).setValues(aSrc);
}
The Script ran perfectly the first time but now is throwing the Service Time Out Error. Is there a way I can make it more efficient? The data is somewhat large ( around 25000 rows and 12 columns).

copyTo using {contentsOnly:true} not working

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");
}