Google Sheets Apps Script: Copy selected Cells into new Worksheet - google-apps-script

I'm new to Apps Script and don't know how I can get my selected cells copied into another worksheet.
I want the following but instead of copying A7:A9 into a new worksheet i want the cells/range that are selected at the time to be copied. the selected cells/range are going to be different each time that i want to use the script.
var rangeList = SpreadsheetApp.getActiveRangeList();
function TestMakro() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A7:A9').activate();
spreadsheet.insertSheet(1);
spreadsheet.getRange('Tabellenblatt1!A7:A9').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
};
thanks

So instead of using SpreadsheetApp.getActive() it's better to define separately the spreadsheet and the active range. you can then get A1 annotation of the active range to find the same area in the new sheet (I assumed that is what you are trying to achieve). Key here is that even if you create a new sheet, it doesn't become Active. Hence you still need to find the same range in it.
Here is the code:
function TestMakro() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const activeRange = spreadsheet.getActiveRange();
const newSheet = spreadsheet.insertSheet(1)
activeRange.copyTo(newSheet.getRange(activeRange.getA1Notation()) , SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false)
}

Related

Trigger when change is happening in specific sheet

I have a sheet with data that is imported through IMPORTRANGE to another sheet. When I make changes to Spreadsheet 1 >>> Spreadsheet 2 I have a script that copy the data from Copy to Paste. It is working all fine however I want to make sure that the script only runs when changes are made in the 'Copy' sheet and not any other. At the moment it runs independent on what sheet I make changes in.
Spreadsheet 1
Spreadsheet2
I tried onChange trigger two different ways...
This one makes the change but triggers when changes are made in any of the sheets
function Trigger2(e) {
var sheet = e.source.getActiveSheet();
if (sheet.getName() === 'Copy') {
copyInfo();
}
}
AND
(this does not work)
function Trigger2(e) {
var sheet = e.source.getActiveSheet();
var sheet = SpreadsheetApp.getActiveSpreadsheet();
if( sheet.getActiveSheet().getName() !== "Copy" ) return;{
copyInfo();
}}
The copy code looks like this...
function copyInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
// get source range
var source = copySheet.getRange(2,1,12,8);
// get destination range
var destination = pasteSheet.getRange(2,1,12,8);
// copy values to destination range
source.copyTo(destination);
}
Copy Changes from one Sheet To Another after Imported Range Changes
Spreadsheet 2 Imports a range to Sheet1 from Spreadsheet 1 Sheet1 and when a change occurs in Spreadsheet 2 Sheet1 we copy data from Spreadsheet2 Sheet1 to Spreadsheet2 Sheet 2.
function onMyChange(e) {
//Logger.log(JSON.stringify(e));//useful during setup
//e.source.toast("Entry");//useful during setup
const sh = e.source.getSheetByName("Sheet1")
Logger.log(sh.getName());
if(e.changeType == "OTHER") {
let tsh = e.source.getSheetByName("Sheet2");
sh.getRange(2,1,12,8).copyTo(tsh.getRange(2,1));//Only need the upper left hand corner of the range. Thus you change change the size of the source data without having to change the target range.
}
}
One might be inclined to attempt to use e.source.getActiveSheet() unfortunately this does not necessary get the sheet that you have written unless in is SpreadsheetApp.getActive().getSheets()[0]. onChange event object always returns the most left sheet in the spreadsheet in this situation so it can't be used to identify the sheet that is being written to from the importRange function.
With this function you no longer require another function.
A simple if should work, but you're trying to compare the name to the wrong field. According to Google's documentation, the source field in the Event Object e returns the Spreadsheet object, which is the entire document.
Instead you can use the e.range field, which contains the exact range where the edit was made, and the Range class has a getSheet() method to get the parent Sheet.
So you can modify your sample to the following:
function Trigger2(e) {
var sheet = e.range.getSheet();
if (sheet.getName() === 'Copy') {//Edit: this will only work if sheet is the most left sheet in the spreadsheet
copyInfo();
}
}

Script to cause an ImportRange function to run on demand

first, let me say, i am not a programmer, but i understand and can build spreadsheet ok. I'm newer to doing so in Google Sheets. I am using an Importrange function to copy date from one spreadsheet tab to another spreadsheet. I'm finding that there is a delay in the updating. I checked my Settings for recalculations and Google Sheets is set to refresh when data is changed. However, its not doing so. So, i wanted to create a button the user can hit and force the ImportRange refresh.
I found some code that appears to accomplish this, but I can't get it to work:
function myFunction() {
SpreadsheetApp.getActive().getRange('A1').setValue('IMPORTRANGE('https://docs.google.com/spreadsheets/d/abcd123abcd123', 'sheet1!A:B')')
}
Here is my import range which is in CELL C4 of a sheet named CALCS:
=importrange("https://docs.google.com/spreadsheets/d/1B5PEI5f4-TAhS77-poCYTiWI6w2t2BEzfiP5kXVq9lk/edit#gid=1661941505","PO TRACKING!A4:T1000")
Welcome to the wonderful world of scripts! There is so much you can do with your projects when using Google Apps Script.
Your question is a good one but I took a different approach. Rather than using an import range that needs to be recalculated, I just wrote a script that would do a similar thing. If you need to collect a specific range of data instead of the entire sheet, then just make one small change to the script provided.
//CHANGE
var poData = poTab.getDataRange().getValues();
//TO
var poData = poTab.getRange('INSERT A1 NOTATION HERE').getValues();
That should allow you to select a specifc range if needed.
//TRANSFER DATA FROM ONE TAB TO ANOTHER
function transferFromSameSpreadsheet() {
//GETS ACTIVE SPREADSHEET
var ss = SpreadsheetApp.getActiveSpreadsheet();
//GETS SPECIFIC SHEET BY NAME WHERE DATA IS STORED
var poTab = ss.getSheetByName('Po Tracking');
//STORES ALL DATA FROM SHEET
var poData = poTab.getDataRange().getValues();
//GETS SPECIFIC SHEET BY NAME WHERE DATA IS SENT
var transferTo = ss.getSheetByName('insert sheet name here');
//CLEARS OLD DATA
transferTo.clearContents();
//UPDATES SHEET WITH NEW DATA
transferTo.getRange(1,1,poData.length,poData[0].length).setValues(poData);
}
//TRANSFER DATA FROM A MASTER SHEET TO ANOTHER WORKBOOK. RUN SCRIPT IN ACTIVE WORKBOOK, NOT MASTER.
function transferFromDifferentSpreadsheet() {
//OPENS SPREADSHEET BY ID
var ms = SpreadsheetApp.openById('insert spreadsheet id here');
//GETS ACTIVE SPREADSHEET
var ss = SpreadsheetApp.getActiveSpreadsheet();
//GETS SPECIFIC SHEET BY NAME WHERE DATA IS STORED
var poTab = ms.getSheetByName('Po Tracking');
//STORES ALL DATA FROM SHEET
var poData = poTab.getDataRange().getValues();
//GETS SPECIFIC SHEET BY NAME WHERE DATA IS SENT
var transferTo = ss.getSheetByName('insert sheet name here');
//CLEARS OLD DATA
transferTo.clearContents();
//UPDATES SHEET WITH NEW DATA
transferTo.getRange(1,1,poData.length,poData[0].length).setValues(poData);
}
Good luck!
Get range A1 notation documentation: https://developers.google.com/apps-script/reference/spreadsheet/sheet#getrangea1notation
What your code is doing is just setting the cell value as the string you input in the setValue()
If you want to input formula you can either include "=" when using setValue() or use setFormula() method
Sample:
function myFunction() {
SpreadsheetApp.getActive().getRange('A1').setFormula('IMPORTRANGE("https://docs.google.com/spreadsheets/d/xxxxx", "sheet1!A:B")');
SpreadsheetApp.getActive().getRange('D1').setValue('=IMPORTRANGE("https://docs.google.com/spreadsheets/d/xxxxx", "sheet1!A:B")');
}
Note:
I also fixed the string format in your code so that it will provide a string input to the setValue() and setFormula()
References:
Range.setValue()
Range.setFormula()

Can I protect the name of a Google sheet? Or reference the sheet by position rather than name?

I manage a Google spreadsheet that has multiple sheets. I use scripts to automate some processes on the first sheet. Recently, a user accidentally renamed the first sheet -so the script stopped working until I found out and corrected the name of the sheet.
My question is: how can I protect against this happening again? Is there a way to protect the sheet name from being changed by users other than myself? Or, in the script, is there a different way to reference the first sheet, regardless of its name? I.e., instead of sheet.getSheetName is there something like sheet.getFirst that returns the first sheet, regardless of its name?
Here's a sample of one script that is being affected.
function onOpen(){
//Sheet where this script should run
var SHEETNAME = "Scan IN Check OUT"
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if (sheet.getSheetName() == SHEETNAME ) { //Check we are on the correct sheet
var sheet = SpreadsheetApp.getActiveSheet();
//Find the last cell with data in that specific column (A in this case)
var lastCell = sheet.getRange('A1').getNextDataCell(SpreadsheetApp.Direction.DOWN);
//Activate the next cell
lastCell.offset(1, 0).activate();
}
}
SpreadsheetApp.getActive().getSheets()[0]; will always be the first sheet on the left which may not always be the same sheet since users can change their position. You can use the first function below to see how the indexes change as you move sheets around. WARNING: don't do this in a spreadsheet that contains important information because it first clears the sheet and then writes the name, the id's and the indexes for all sheets.
So you can also use the first function to get the id of the sheet that you want not to change.
The second function will get the sheet by id. If you will select the id of your sheet and replace the string 'My Sheet ID' with it and also put the correct name of your sheet where it says my sheet name, then when you runTwo() it will move you sheets all the way to left (ie index 1) and rename to whatever you want.
function runOne() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var sht=ss.getSheets();
sh.clear();
sh.appendRow(['Name','id','index']);
sht.forEach(function(s){
sh.appendRow([s.getName(),s.getSheetId(),s.getIndex()]);
});
}
function getSheetById(id) {
var id=id||'My Sheet ID';
var ss=SpreadsheetApp.getActive();
var shts=ss.getSheets();
for(var i=0;i<shts.length;i++) {
if(shts[i].getSheetId()==id) {
return shts[i];
}
}
}
function runTwo() {
var ss=SpreadsheetApp.getActive();
var sh=getSheetById().activate();
ss.moveActiveSheet(1);
sh.setName('My Sheet Name');
}
Of course the real problem here is that if the user can change the name of your sheet they can also go in and change your script.

How come this function isn't returning anything in Google Sheets?

I'm trying to be able to access information on the active sheet, but I can't even seem to "connect" with the sheet to begin with. I'm just wondering why this small function isn't returning anything.
I've played around with different ways to call the sheet (e.g. getActive(), getActiveSheet(), getSheetByName(), etc.), and changing the name of the sheet itself.
function CLICK (){
var sheetName = SpreadsheetApp.getActiveSheet();
return sheetName;
}
I just want it to return the sheet name so I know it's accessing the sheet properly.
For your var please try:
sheetName = SpreadsheetApp.getActiveSheet().getName();
Hi there are some different options you can choose depending on what you want to do. I would suggest to read https://developers.google.com/apps-script/guides/sheets. Here are the examples I have for you.
function myFunction() {
/* To work on the first sheet sheet of the Spreadsheet, use getName(); to get the name of the spreadsheet*/
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
/* To get the name of the active sheet*/
var sheet2 = SpreadsheetApp.getActiveSheet().getName();
/* To add values on the active cell (current selected cell)*/
var sheet3 = SpreadsheetApp.getActiveRange().setValue(sheet2);
/*To work on the sheet with a specific Name*/
var sheet4 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
console.log(sheet2);
console.log(sheet4);
/*The difference between getSheets()[0] and getSheetByName("name") is that getSheets()[0]
will always work with the first sheet even if you change position and getSheetByName() will
always work with the sheet you named even if you change position, the position is 0 based*/
}
Here is another function to get name, url and id of the srpeadsheet.
function getDetails(){
var getName = SpreadsheetApp.getActiveSpreadsheet().getName();
var getUrl = SpreadsheetApp.getActiveSpreadsheet().getUrl();
var getId = SpreadsheetApp.getActiveSpreadsheet().getId();
console.log(getName);
console.log(getUrl);
console.log(getId);
}
Remember that if you are using a script editor that is attached to the Spreadsheet for sure you will be working on that spreadsheet. Now if you created a new script directly from script.google.com then you will need to first open the spreadsheet by using an Id or a url to open that specific spreadsheet.
I hope this helps.

Why can't I copy ranges between spreadsheets with copyValuesToRange()?

I am able to copy a range of values from one spreadsheet to another with Range.setValues(values) but not with Range.copyValuesToRange(sheet, column, columnEnd, row, rowEnd):
function test()
{
var sourceSheet = SpreadsheetApp.getActiveSheet();
var sourceCols = sourceSheet.getRange("A1:B10");
// Copying the first two columns this way works.
var sheet1 = SpreadsheetApp.create("New Spreadsheet 1").getActiveSheet();
sheet1.getRange("A1:B10").setValues(sourceCols.getValues());
// Copying the first two columns this way does not work.
var sheet2 = SpreadsheetApp.create("New Spreadsheet 2").getActiveSheet();
sourceCols.copyValuesToRange(sheet2, 1, 2, 1, 10);
}
Specifically, after running the code, New Spreadsheet 1 contains range A1:B10 of the source spreadsheet, while New Spreadsheet 2 is empty. Both have a single sheet named "Sheet1". The source spreadsheet is unmodified.
What am I doing wrong? I'm wondering if the failing method only works within a single spreadsheet, but I see nothing in the documentation about that.
The reason I want to use Range.copyValuesToRange() is so I can also copy the formatting with Range.copyFormatToRange().
The methods copyValuesToRange and copyFormatToRange, as well as Range.copyTo, are restricted to copying within the same spreadsheets, although documentation is not explicit about that. A workaround which allows you to copy between spreadsheets with formatting is to copy the entire sheet to the destination spreadsheet, using Sheet.copyTo method. Then copy the required range from there, and optionally, delete the sheet. Like this:
function cc() {
var ss1 = SpreadsheetApp.openByUrl('some url');
var ss2 = SpreadsheetApp.openByUrl('another url');
var sheet1 = ss1.getSheetByName('name');
var sheet2 = ss2.getSheetByName('another name');
// the above was the setup, main code begins here
var copySheet = sheet1.copyTo(ss2);
copySheet.getRange("A1:B2").copyTo(sh2.getRange("C1:D2"));
ss2.deleteSheet(copySheet);
}