Apps Script: Copy rows to another sheet without the headers/headlines - google-apps-script

ISSUE: I have 2 identical sheets and want to copy all non-empty rows from the first sheet to the second sheet. And this copying process should start at row 2 of column A of the first sheet. In other words, I do NOT want to include the headers/headlines in the copy.
ATTEMPTED SOLUTION: The script below copies the whole first sheet (including the headers/headline) instead of starting to copy at row 2. I am pretty sure I am missing something and won´t be able to find it out, as I am still learning how to deal with Apps Script.
QUESTION: Can somebody please correct the code below, so that it can copy only the non-empty rows from the first sheet to the second sheet and without the headers/headline?
Thank you so much in advance.
function copyAndAddNewEntries() {
var sourceSheet = SpreadsheetApp.openById('SOURCE_SHEET_ID').getSheetByName('SOURCE_SHEET_NAME')
var sourceSheetrange = sourceSheet.getDataRange();
var sourceSheetData = sourceSheetrange.getValues();
var targetSheet = SpreadsheetApp.openById('TARGET_SHEET_ID').getSheetByName('TARGET_SHEET_NAME');
targetSheet.getRange(targetSheet.getLastRow() + 1, 1, sourceSheetrange.getHeight(), sourceSheetrange.getWidth()).setValues(sourceSheetData);
}

I believe your goal as follows.
You want to copy the rows that all empty columns are not empty from the source sheet, and want to put the values to the destination sheet.
You want to remove the header row from the source values.
In this case, how about the following modification?
Modified script:
function copyAndAddNewEntries() {
var sourceSheet = SpreadsheetApp.openById('SOURCE_SHEET_ID').getSheetByName('SOURCE_SHEET_NAME');
var sourceSheetrange = sourceSheet.getDataRange();
var [, ...sourceSheetData] = sourceSheetrange.getValues();
sourceSheetData = sourceSheetData.filter(e => e.join("") != "");
var targetSheet = SpreadsheetApp.openById('TARGET_SHEET_ID').getSheetByName('TARGET_SHEET_NAME');
targetSheet.getRange(targetSheet.getLastRow() + 1, 1, sourceSheetData.length, sourceSheetData[0].length).setValues(sourceSheetData);
}
Reference:
filter()

Related

When row is added it should keep all formulas

I have been trying to add a row which keep the formulas.
But when i add any row it always empty.
I could not found a way by searching on google.
I have attached below example sheet. Any help would be greatly appreciate
https://docs.google.com/spreadsheets/d/1HiOrz1KAuV1nN9a2IlwQgv3aWrGNKFaKHq2a8JZw3gI/edit#gid=0
Explanation:
Your goal is to copy the formulas to the newly inserted row upon inserting a new row.
You can use an onChange which has a property INSERT_ROW and
make sure you activate some code when you insert a new row.
The following script will copy the content and formulas from the above row of the one which was inserted to the newly inserted row upon inserting a new row.
Solution:
Add both code snippets below to the script editor:
function myFunction(e) {
const sh = SpreadsheetApp.getActiveSheet();
if(e.changeType === 'INSERT_ROW') {
const row = sh.getActiveRange().getRow();
var fromRng = sh.getRange(row-1,1,1,sh.getLastColumn());
var toRng = sh.getRange(row,1,1,sh.getLastColumn());
fromRng.copyTo(toRng);
}
}
and execute this function createTrigger only and once to create the onChange trigger:
function createTrigger(){
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)
.onChange()
.create();
}
Illustration:
Limitation:
The disadvantage of this approach is that is copies both values and formulas, but it does not seem to matter in your case since you have only formulas as of now. If you want to put only formulas you need to use setFormulaR1C1 but since you have cells with no formulas, you need to make sure that you copy formulas, otherwise you will get errors.
This should let you copy your last row, including data and formula, into its next row.
function addRow() {
var sh = SpreadsheetApp.getActiveSheet();
var lastRow = sh.getLastRow();
var lastCol = sh.getLastColumn();
var range = sh.getRange(lastRow, 1, 1, lastCol);
sh.insertRowsAfter(lastRow, 1);
range.copyTo(sh.getRange(lastRow + 1, 1, 1, lastCol), {contentsOnly:false});
}
The important parameter you need in copyTo here is {contentsOnly:false}. Feel free to modify the coordinates for you to paste the row to anywhere.
For more details, read the usage of copyTo
If you want only the formula in the newly added row, you need to get the formula from the source row and then copy it to your destination row.
var source = sheet.getRange("A1:C1");
var dest = sheet.getRange("A2:C2");
var arr = source.getFormulas();
dest.setFormulas(arr);
This doesn't adjust the formula to the new row, it will copy the exact cell formula so be careful.

Trying to build G Sheets scrip that will copy and paste a dynamic range within same spreadsheet

I'm trying to build a script that will allow me to copy and value paste a range from tab "robert" to tab "brendan". However, the range in "robert" is dynamic, so sometimes it will need to copy and paste A1:M3 or A1:M20. I'd also like it to append to the the first rows of the destination. So when run, the script looks for values on the source tab (robert), copies them, and pastes their values at the top of the destination (brendan) without overwriting existing data.
So far I've worked with the below script from a different thread:
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange('Robert!A1:M100');
source.copyTo(ss.getRange('Brendan!A4'), {contentsOnly: true});
source.clear();
}
The problem here is the script range is static, and it overwrites anything in the destination. I do like the clearing of the source though and the values paste. Any help would be greatly appreciated!
Define the range using variables. Use getLastRow() and getLastColumn() Instead of hard-coding it.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var robWs = ss.getSheetByName("Robert");
var brenWs = ss.getSheetByName("Brendan");
var robLr = robWs.getLastRow()
var robLc = robWs.getLastColumn()
//range starts at row 1 and column 1 (A1), you may need to change accordingly
var vals = robWs.getRange(1,1,lr,lc).getValues;
//paste range also starts at A1. you can find the lr on this sheet and start the range there
brenWs.getRange(1,1,lr,lc).setValues(vals);
function moveValuesOnly() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Robert');
var rg=sh.getActiveRange();//copies active range for source
var vA=rg.getValues();
dsh=ss.getSheetByName('Brendan');
dsr=4;//destination start row
dsc=1;//destination start col
dsa=2;//destination number of rows to append to
drg=dsh.getRange(dsr,dsc,rg.getHeight(),rg.getWidth());
var dvA=drg.getValues();
vA.forEach(function(r,i){
if(i<dsa){
r.forEach(function(c,j){
//only write data in destination for these rows if destination value is null
if(dvA[i][j]='') {
dvA[i][j]=c;
}
});
}else{
dvA[i][j]=c;
}
})
drg.setValues(dvA);
}

Script to copy and paste values to the first empty row in Google spreadsheets with zero in front of other numbers

So the code copies the content of Sheet1 B2:G2, B2 cell contains a code that often starts with multiple 0. Everything is okay in Sheet1, but once the script is executed and it is copied to Sheet2, the format changes to "Automatic and "000001" becomes just "1". I can't seem to find a away to make it instantyl format as plain text to keep the 0 in front. Also, the G cell contains €, so I don't want to set entire row as plain text, just the B column.
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange("Sheet1!B2:G2");
var destSheet = ss.getSheetByName("Sheet2");
destSheet.appendRow(source.getValues()[0]);
}
How about this modification? I think that there are several solutions for your situation. So please think of this as just one of them. In this modification, 2 lines were added to your script.
Modification point:
After appendRow() was run, the format of "Sheet1!B2:G2" is copied to the appended row. By this, "000001" is displayed.
Modified script:
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange("Sheet1!B2:G2");
var destSheet = ss.getSheetByName("Sheet2");
destSheet.appendRow(source.getValues()[0]);
var destination = destSheet.getRange(destSheet.getLastRow(), 1); // Added
source.copyTo(destination, SpreadsheetApp.CopyPasteType.PASTE_FORMAT) // Added
}
References:
copyTo()
Enum CopyPasteType
If this was not the result you want, please tell me. I would like to modify it.
Thank you for this thread. I had a slightly different problem to solve but this gave me the inspiration to do it and thought I'd share. I wanted to update columns D:I with existing formulas from D7:I7 any time an edit was made to the spreadsheet. (In my case, that is most often just adding data to a new row A:C.) I only wanted it to fire if one particular Sheet was modified (not the other sheets).
This seems to do the trick nicely.
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sName = ss.getSheetName();
Logger.log('Starting script...');
if (sName == 'Data'){
Logger.log('We are editing the sheet name: "' + sName +'"'
);
var source = ss.getRange("Data!D7:I7");
var destSheet = ss.getSheetByName("Data");
var lastRow = destSheet.getLastRow();
var destination = destSheet.getRange("D"+lastRow);
destination.activate();
source.copyTo(destination, SpreadsheetApp.CopyPasteType.PASTE_FORMULA)
} else
Logger.log('Nothing Done. Sheet name: "' + sName + '"' );
}

Set values to ranges in a different spreadsheet

Can anybody offer suggestions about how to update or set values to a range in a different spreadsheet. I know the importRange function will bring values into the active sheet, but I want to "push" a single row of data from the active sheet to a row at the bottom of a sheet called FinalData, which is in a different spreadsheet.
The data I want to "push" is populated by other code, resulting in a single row of data in a sheet called TempData. The data exists in range TempData!A2:U2.
My goal is to append data from TempData!A2:U2 to a new row at the bottom of a table called "DataFinal", which is in a completely separate google spreadsheet (but on the same "google drive".)
Here's what I tried so far:
// Row to FinalData
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var startSheet = ss.getSheetByName("TempData");
var sourceRange = ss.getRange ("TempData!A2:U");
var target = SpreadsheetApp.openById("1bWKS_Z1JwLSCO5WSq1iNP1LLQpVXnspA4WkzdyxYDNY");
var targetSheet = target.getSheetByName("DataFinal");
var lastRow = targetSheet.getLastRow();
targetSheet.insertRowAfter(lastRow);
sourceRange.copyTo(targetSheet.getRange(lastRow + 1,1), {contentsOnly: true});
When I run it I get an error that says "Target range and source range must be on the same spreadsheet.". There must be a way to do this-- any suggestions would be welcome.
copyTo() can be used for the same spreadsheet.
From your script, I think that you can achieve it using getValues() and setValues(), because you use contentsOnly: true. So how about this modification?
From :
sourceRange.copyTo(targetSheet.getRange(lastRow + 1,1), {contentsOnly: true})
To :
var sourceValues = sourceRange.getValues();
targetSheet.getRange(lastRow + 1, 1, sourceValues.length, sourceValues[0].length).setValues(sourceValues);
Note :
If you want to use copyTo(), this thread might be useful for your situation.
References :
copyTo()
getValues()
setValues()
If this was not what you want, please tell me. I would like to modify it.

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