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.
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 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.
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);
}
I have trouble understanding arrays, but I know it's what I need to do to fix my problem. Presently, I'm copying data I need from another sheet onto a tab, copying that data table, then pasting it into another tab on that sheet. I now need to add another column to the end of this finally produced data that is a formula in each cell adjacent, which is column AP starting in AP2. Here is the script:
function CopyDataToNewFile() {
var sss = SpreadsheetApp.openById('some id');
var ss = sss.getSheetByName('Outcome'); // ss = source sheet
var destination = SpreadsheetApp.openById('other id');
var target = destination.getSheetByName('Final');
ss.copyTo(destination);
var data = destination.getSheetByName('Copy of Outcome');
var infoTable = data.getRange(2, 1, data.getLastRow(), data.getLastColumn());
var lastRow = target.getLastRow();
infoTable.copyTo(target.getRange(lastRow + 1, 1), {contentsOnly: true});
destination.setActiveSheet(destination.getSheetByName('Copy of Outcome'));
destination.deleteActiveSheet();
}
The formula I want to append each copied row with is the following:
'=vlookup($I2, IMPORTRANGE("https://docs.google.com/spreadsheets/d/<yet another id>/edit#gid=1203869430", "Source_Hours!A:B"), 2, false)'
Here's how I tried to do it:
function CopyDataToNewFile() {
var sss = SpreadsheetApp.openById('some id');
var ss = sss.getSheetByName('Outcome'); // ss = source sheet
var destination = SpreadsheetApp.openById('other id');
var target = destination.getSheetByName('Final');
ss.copyTo(destination);
var data = destination.getSheetByName('Copy of Outcome');
var infoTable = data.getRange(2, 1, data.getLastRow(), data.getLastColumn());
var lastRow = target.getLastRow();
infoTable.copyTo(target.getRange(lastRow + 1, 1), {contentsOnly: true});
target.getRange(2,infoTable.getLastColumn()+1,infoTable.getLastRow(),1).setFormula('=vlookup($I2,IMPORTRANGE("https://docs.google.com/spreadsheets/d/1f7_unFqRkI6O2EHBLsNGLRCH5j9rlEXBdVnRLTgS_lM/edit#gid=1203869430","Source_Hours!A:B"),2,false)');
destination.setActiveSheet(destination.getSheetByName('Copy of Outcome'));
destination.deleteActiveSheet();
}
It works the first time I run the script, but the next time I run it, it does not add the formula in the last column. I am not a programmer, just know enough to be dangerous. :)
Your solution was close. My recommended approach is to create a reference to the first row your script will copy into -- target.getLastRow() + 1 -- and then use this reference for both the datatable copy, and the formula write. Your script also had a possible issue in that you assumed that the sheet name was always "Copy of Outcome" -- this is not strictly guaranteed to be true (consider copying a sheet twice without deleting the first copy). Instead, bind the return value of Sheet#copyTo, since it is the newly created worksheet copy. In this manner, the name of the copied sheet is irrelevant - the script doesn't need it to function as intended.
function CopyDataToNewFile() {
const source = SpreadsheetApp.openById('some id').getSheetByName('Outcome');
const destination = SpreadsheetApp.openById('other id');
const target = destination.getSheetByName('Final');
if (!source || !target)
throw new Error("Missing required worksheets (sheet names not found)");
// Copy the source sheet and get a reference to the copy.
var datasheet = source.copyTo(destination);
var infoTable = datasheet.getRange(2, 1, datasheet.getLastRow(), datasheet.getLastColumn());
// Copy the table contents to the end of the target sheet.
// Determine the first row we are writing data into.
const startRow = target.getLastRow() + 1;
infoTable.copyTo(target.getRange(startRow, 1), {contentsOnly: true});
// Set a column formula in the adjacent column.
target.getRange(startRow, 1 + infoTable.getNumColumns(), infoTable.getNumRows(), 1)
.setFormula("some formula");
// Remove the intermediate sheet.
destination.deleteSheet(datasheet);
}
New functions used:
Spreadsheet#deleteSheet (you don't have to activate a sheet to delete it)
Range#getNumColumns The width of the Range
Range#getNumRows The height of the Range
An alternate method, which uses JavaScript arrays to limit the number of Spreadsheet Service methods used, is possible since you appear to only desire the values to be transferred. This takes advantage of chaining, since Range#setValues returns a reference to the range that was written into. This assumes that values on the source sheet, "Outcome", don't depend on the workbook. If "Outcome" has formulas that refer to other worksheets in the same workbook, then naturally this won't work, as the values would be in reference to the original workbook, not the destination workbook.
...
const dataToCopy = source.getDataRange().getValues();
dataToCopy.shift(); // remove header row.
const startRow = target.getLastRow() + 1;
const numRows = dataToCopy.length;
const numColumns = dataToCopy[0].length;
target
.getRange(startRow, 1, numRows, numColumns)
.setValues(dataToCopy)
.offset(0, numColumns, numRows, 1) // offset is from the top-right cell of the range
.setFormula("some formula");
}
Range#offset
Array#shift
In Google Spreadsheet I would like to take only the values from a complete list on one spreadsheet and append it to the bottom of a list on another spreadsheet. My trouble is that using the the copyValuesToRange() function errors the following:
Target sheet and source range must be on the same spreadsheet.
Here's my current code:
function transferList() {
var source = SpreadsheetApp.getActiveSpreadsheet();
var target = SpreadsheetApp.openById("0ABCD");
var target_sheet = target.getSheetByName("RFPData");
var sheet = source.getSheetByName("RFP List");
var sheet_last_row = sheet.getLastRow() + 1;
var source_range = sheet.getRange("A2:I"+sheet_last_row);
var sWidth=source_range.getWidth() + 1;
var sHeight=source_range.getHeight() + 1;
var last_row=target_sheet.getLastRow();
source_range.copyValuesToRange(target_sheet , 1, sWidth,
last_row + 1, last_row + sHeight );
}
Any idea how I can get this to work?
As you've found, copyValuesToRange() is a Range method that affects a Sheet Object that is in the same Spreadsheet Object as the Range. There isn't an atomic method that will copy a range of values to another Spreadsheet, but there are a number of ways you could do it.
Here's one way.
From the source sheet, get all the data in one operation, by selecting the complete range of data using getDataRange() and then grabbing all values into a javascript array with getValues().
To ignore the first row of headers, use the javascript array method splice().
Locate your destination, which is on the target sheet, starting after the last row of data that's currently there, using getLastRow().
Write the source data (without the headers) to the destination sheet starting at the next row, using setValues().
Script:
function transferList() {
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("RFP List");
var sourceData = sourceSheet.getDataRange().getValues();
sourceData.splice(0,1); // Remove header
var targetSS = SpreadsheetApp.openById("0ABCD").getSheetByName("RFPData");
var targetRangeTop = targetSS.getLastRow(); // Get # rows currently in target
targetSS.getRange(targetRangeTop+1,1,sourceData.length,sourceData[0].length).setValues(sourceData);
}
For some historic dashboard I created by importing and appending data, I use an add-on called Sheetgo. Save me programing time and help me with traceability issues.