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.
Related
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()
I wrote a script that is supposed to append a row to a filtered range within a Google Sheets. My script works in normal situation. But when the last row of the destination range is deleted AND the range is filtered on one of the fields (image below illustrates the situation), the appendRow does not work.
Screenshot of the situations where appendRow does/doesn't work:
[1
Here is my code:
function myFunction() {
outputRowArray = [1,2];
destinationUrl = "XXX";
destinationSheet = "Sheet1"
SpreadsheetApp.openByUrl(destinationUrl).getSheetByName(destinationSheet).appendRow(outputRowArray);
}
You are missing that appendRow appends a row to the sheet, that means that the row is added after the last row with data in sheet. Also you are missing that the filter boundaries are only updated when inserting a row/column that are part of the filter range (this should be done between two rows/columns) but not when appending them (inserting the row/column after the last row/column of the filter range)
On the past I have seeing similar questions claiming that appendRows don't work but what was happening is that the sheet include some values (sometimes an empty string) several rows below of the rows shows in the screen.
To help you to understand what is happening log some sheets characteristics by using Class Sheets methods like
getLastRow()
getMaxRows()
To log things you could use Logger.log(something) and console.log(something). for further details checkout https://developers.google.com/apps-script/guides/support/troubleshooting
Something else to try is to log the last row after appending a new row, but bear in mind that you might need to use SpreadsheetApp.flush() first. Example:
function myFunction() {
outputRowArray = [1,2];
destinationUrl = "XXX";
destinationSheet = "Sheet1"
var sheet = SpreadsheetApp.openByUrl(destinationUrl).getSheetByName(destinationSheet);
sheet.appendRow(outputRowArray);
SpreadsheetApp.flush();
var lastRow = sheet.getLastRow();
console.info(lastRow);
}
More than a work around then a solution.
function myFunction() {
outputRowArray = [1,2];
destinationUrl = "XXX";
destinationSheet = "Sheet1"
var sheet = SpreadsheetApp.openByUrl(destinationUrl).getSheetByName(destinationSheet)
var last_row = sheet.getLastRow()
var insert_range = sheet.getRange(last_row+1,1,1,outputRowArray.length()) // not really sure that I got right the dims
insert_range.setValues([outputRowArray])
}
I have a Google spreadsheet that contains 3 tables(let's say each are 5 rows by 5 columns).
When I need to add a new row to one of the tables I just copy the last row from that table below(so I can have the formulas in the new row as well) and then re-edit it with the new values.
I would like however to have an easier solution for doing this. I want to select a row and then run a script. The script will copy the selected row below and initialize all cells with empty values.
I have googled around but I found nothing that could help me :(. I have found some scripts that are supposed to copy the last row and carry the formulas such as this one:
// global
var ss = SpreadsheetApp.getActive();
function onOpen() {
var menu = [{name:"Add New Last Row", functionName:"addRow"}];
ss.addMenu("Extra", menu);
}
function addRow() {
var sh = ss.getActiveSheet(), lRow = sh.getLastRow();
var lCol = sh.getLastColumn(), range = sh.getRange(lRow,1,1,lCol);
sh.insertRowsAfter(lRow, 1);
range.copyTo(sh.getRange(lRow+1, 1, 1, lCol), {contentsOnly:false});
}
I wanted to start from that one and then try to modify the script to do what I want. However, I was not able to do so. When I create a new script and paste that code the script becomes 'unrunnable' :(. I understand that onOpen() is something called a 'trigger' which is some sort of reserved function name(or something like that). Does that have something to do with my script being unrunnable?
Please explain how can I get that copied script to run like a normal script and also give me any tips in achieving what I want(adding a row with the formulas from the row above at a specific location).
For now since you just want to update the functionality don't worry about the onOpen and the menu just run addRow().
I rewrote it a little bit like so:
function addRow() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var lr=sh.getLastRow();
var lc=sh.getLastColumn();
var rg=sh.getRange(lr,1,1,lc);
sh.insertRowsAfter(lr, 1);
rg.copyTo(sh.getRange(lr+1,1,1,lc), {contentsOnly:false});
}
So now you have everything you need to get addRow to work. From there we can discuss further what you would like to change.
This version uses the selected row instead of the last row.
function addRow() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var lr=sh.getActiveCell().getRow();
var lc=sh.getLastColumn();
var rg=sh.getRange(lr,1,1,lc);
sh.insertRowsAfter(lr, 1);
rg.copyTo(sh.getRange(lr+1,1,1,lc), {contentsOnly:false});
}
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.
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);
}