Duplicate Sheet in Google Sheets leaving Custom Script behind - google-apps-script

I recently added a script within the Script Editor of Google Sheets to auto-sort my page based on values in Column D. It was set up to apply to the active sheet – Let's call it 'Sheet A'
Sheet A is used so people can view the data sort in descending order, which is great. Every time a change/edit is made to Sheet A, the data automatically resorts itself.
I did plenty of cell merging, styling, conditional formatting, etc in Sheet A that I don't want to have to recreate it. So I duplicated Sheet A – let's call it 'Sheet B' and applied Data > Sort Range alphabetical (Column E is names) so that people can have to option to view this way and find themselves much quicker than they would in Sheet A.
THE ISSUE: The custom script I added in Sheet A is being carried over into Sheet B – so anytime I make an edit, Sheet B auto-sorts by descending order from values in Column D.
Is it possible to duplicate my Sheet A but not keep the script in the copy (Sheet B)? Or is there a better way to migrate Sheet A to Sheet B that ignores the script coming with it all together?

There is no simple way to do copy a spreadsheet without the linked files, either a form or a bounded script.
In your case that the spreadsheet includes simple triggers perhaps the simplest solution is to include a condition to check if the id of the active spreadsheet is equal to the id of the "original" spreadsheet:
function onEdit(e){
if( e.source.getId() !== 'put_here_the_id_of_the_original_spreadsheet') return;
// put here the things to do
}
NOTE: Bounded scripts are bounded to the container (in this case the spreadsheet) not to an specific sheet (page in Google Docs or slide in Google Slides), so leaving a script behind when making a a copy of one sheet doesn't make sense.
If you want that a function only make changes to certain sheet then you should add a condition to compare the name of the active sheet with the name of the "original" sheet
function onEdit(e){
// Get the active sheet
var sheet = e.range.getSheet();
var name = sheet.getName();
if(name !== 'SheetA') return;
// put here the things to do
}
Related
Copying a spreadsheet copies all linked files as well
How can I delete container-bound scripts from multiple Google Documents or Sheets simultaneously without deleting the containers/files?

Related

TypeError: SpreadsheetApp.getActiveSpreadsheet.duplicateActiveSheet is not a function

I'm trying out this bellow script in google app scripts. but I'm having some issues with the duplicate part. I want the "ORIGINAL" Sheet to be duplicated and renamed using cell G1. Sadly it fails at the duplicate part. If I comment out the duplicate code and run the code, the ORIGINAL sheet will just be renamed using the value on G1. How do I make it so when I run it, it duplicates the ORIGINAl sheet and renames the duplicated sheet with the value from G1?
function CreateNewPulseSheet() {
// The code below makes a duplicate of the active sheet
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("ORIGINAL").activate(); //getSheetByName returns a Sheet, but doesn't set it as active
SpreadsheetApp.getActiveSpreadsheet.duplicateActiveSheet(); //Duplicate makes a copy and sets it as the active sheet
// The code below will rename the active sheet to a date based on cell M1 of the source spreadsheet
var myValue = SpreadsheetApp.getActiveSheet().getRange("G1").getDisplayValue();
SpreadsheetApp.getActiveSpreadsheet().renameActiveSheet(myValue);
}
Replace
SpreadsheetApp.getActiveSpreadsheet.duplicateActiveSheet();
by
SpreadsheetApp.getActiveSpreadsheet().duplicateActiveSheet();

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

Update google "master" spreadsheet when other sheets are updated

I have multiple Google spreadsheets with booking data such as booking number, client name, email, booking date etc. The order of these columns is not the same in all sheets.
I would like to update all data from all my "source" sheets in one "master" spreadsheet. Meaning as soon as a new row is added or an existing row is updated, the data will be synced to the master spreadsheet
What would be the best way to achieve that? Javascript or is there some existing Google Sheets addon?
Example sheet 1: Fast boat bookings
Example sheet 2: Airport transfer bookings
Master sheet
Thanks so much to everyone looking into this!
Most people recommend to use "importrange", but I don't think this works for my use case.
I am also aware that it could be achieved by Zapier, but it would become to costly to pay for so many zaps. I believe there is another solution.
I do not have any code yet to start with :-/
I expect the data in the master sheet to be sorted by submission date and time like this:
The general procedure for using formulas is
Use IMPORTRANGE to get the data from the source spreadsheets into the master spreadsheet
Use array notation to put the imported data together
NOTES:
If you are new to using IMPORTRANGE, arrays in Google Sheets and complex formulas, use one sheet for each IMPORTRANGE, and delete the unused columns to save cells because the Google Sheets 5 million cell limit
If you prefer to use scripts, you should get the spreadsheets keys, or URLs then you could use SpreadsheetApp.openById(id) or SpreadsheetApp.openByUrl(url) to open the spreadsheets. Then you could use getValues() / setValues() to read / write the values from source spreadsheets to the master spreadsheet.
References
Using arrays in Google Sheets
Extending Google Sheets with Google Apps Script
Related
Is it possible to do ImportRange in Google Apps Script?
IMPORTRANGE to import multiple Google Sheets into one vertical column?
As a workaround for Apps Script triggers not being fired by automatic sheet updates, you need to use IMPORTRANGE to import your data into a dummy sheet. IMPORTRANGE will detect also through automatic sheet update and simultaneously it is able to fire an onEdit trigger.
Do the following:
Delete all empty rows in MASTER spreadsheet
Create a dummy spreadsheet and import into it the contents of MASTER spreadsheetwith a formula:
From the dummy sheet, open the script editor and insert the following code:
function changed(e) {
var masterSheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
if(PropertiesService.getScriptProperties().getKeys().length==0){
PropertiesService.getScriptProperties().setProperty('startRow', 5);
}
var startRow=PropertiesService.getScriptProperties().getProperty('startRow');
var lastRow=masterSheet.getLastRow();
var numRows=lastRow-startRow+1;
var startCol=1;
var numCols=6;
var values=masterSheet.getRange(startRow,startCol,numRows,numCols).getValues();
var FBsheet=SpreadsheetApp.openById('1SzBx5Q9rrlcLGSqD8y5eFE5TX304LfZ7D9mxxrHhfKw').getSheetByName('Sheet1');
var ATsheet=SpreadsheetApp.openById('1IRD8wT5Kmx7h_xP807f4ibWRn8g98RjA-dJXxADXAl0').getSheetByName('Sheet1');
FBsheet.getRange(FBsheet.getLastRow()+1,startCol, numRows, numCols).setValues(values);
var ATlastRow=ATsheet.getLastRow();
for(var i=0;i<numRows;i++){
Logger.log(values[i][1]);
ATsheet.getRange(ATlastRow+1+i,1, 1, 1).setValue(values[i][1]);
ATsheet.getRange(ATlastRow+1+i,2, 1, 1).setValue(values[i][0]);
ATsheet.getRange(ATlastRow+1+i,3, 1, 1).setValue(values[i][3]);
ATsheet.getRange(ATlastRow+1+i,4, 1, 1).setValue(values[i][2]);
ATsheet.getRange(ATlastRow+1+i,5, 1, 1).setValue(values[i][5]);
ATsheet.getRange(ATlastRow+1+i,6, 1, 1).setValue(values[i][4]);
}
PropertiesService.getScriptProperties().setProperty('startRow', lastRow+1);
}
Attach to the script an onEdit trigger
Run the script once manually, it is normal that it will throw you an error
Now the script will run automatically each time data update takes place in MASTER spreadsheet.
Make sure you change all spreadsheetIDs and sheet names with your
values.

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: How to push data/copy a cell from one google spreadsheet to another google spreadsheet using google apps script?

I look for a solution to copy a specific cell value in the Source spreadsheet from tab "Sum all" to another Spreadsheet to the Target Spreadsheet Tab "Copy all". It should work every time i change the Value of Cell G10. Access to the Target sheet is granted before i enter any Value to G10.
(Source Tab Name is "Sum all:G10" - Sheet has 10 different Tabs)
(Target Tab Name is "CopyData:T12" - Sheet has 10 different Tabs)
Easy way
Use the built-in IMPORTRANGE() function in Google Apps:
In your Target cell, type the following formula
=IMPORTRANGE("FILE_ID_HERE","Sum all!G10:G10")
The syntax for this function is
=IMPORTRANGE("FILE_ID","SHEET_NAME!RANGE_START:RANGE_END")
When you first type in this function, you'll get an error in the cell. Simply click on it and select "Allow" to link the two sheets together. This error will occur even if it is the same spreadsheet. This function can link two separate spreadsheets, too, as long as you have edit access to both.
Hard Way
I'm assuming from your question that you want to copy values to and from the same spreadsheet document, but to different cells that are located on different sheets of the spreadsheet. The Google Apps Script API calls tabs "sheets" and the overall document "spreadsheet".
First, open the script editor
Open your spreadsheet that you'd like to make this script for.
Select "Tools" in the toolbar, then "Script Editor"
Second, make a function for onEdit.
Making a function named onEdit will create a function that runs every time the edit trigger is fired, using a no-authorization "simple trigger". Google Sheets automatically sends this event every time a cell is edited by a user. The argument e for the function is the event passed by the trigger.
function onEdit(e) {
// Get the sheet named "Sum all" from the active spreadsheet (i.e. the one you are editing)
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sum all");
// Returns the active cell
var cell = source .getActiveCell();
// Compare to see if its the right cell you're looking for
// getRow and getColumn methods return integers for the row and column of the cell
// A = 1, B = 2, ... G = 7
if (cell.getRow() == 10 && cell.getColumn() == 7) {
// If its the right cell, copy to the other cell
var target = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CopyData");
// set the value of the desired cell in the target sheet
target.getRange("T12").setValue(cell.getValue());
}
}
Third, save the script
Save the script, reload the file, and test it out.
If your tabs are on different spreadsheets
Change this line:
var target = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CopyData");
to this:
var target = SpreadsheetApp.openById("FILE_ID").getSheetByName("CopyData");
and insert the file ID for the target spreadsheet where I've written FILE_ID.
You will also need to use an "installed trigger", since a simple trigger cannot open a remote spreadsheet. To do this, change the name (so it is no longer a simple trigger function), and follow the steps here