GAS Class SpreadsheetApp : Append Row and Merge Cell - google-apps-script

I wish it was this simple but this doesn't work.
sheet.appendRow(['MERGE', '']).merge();
How can I achieve this?

The method merge() needs to be applied to a range object.
One possibility to do so would be:
function myFunction() {
var sheet = SpreadsheetApp.getActive().getActiveSheet();
var newRow=sheet.getLastRow()+1;
// the range dimensions should match the value array dimensions
var range=sheet.getRange(newRow,1,1,2);
range.setValues([['MERGE', '']]);
range.merge();
}
References:
getRange()
setValues()
merge()
getLastRow()

Append Row
This is just a simple of example of find a row with todays date and appending it to another sheet. In this example, I also delete the current row in the source sheet this making it more of a move command.
function findingRowsAndAppendingToAnotherSheet() {
var ss=SpreadsheetApp.getActive();
var ssh=ss.getSheetByName('Sheet1');
var dsh=ss.getSheetByName('Sheet2');
var srg=ssh.getRange(2,1,ssh.getLastRow()-1,ssh.getLastColumn());
var vA=srg.getValues();
var cdv=new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()).valueOf();
var d=0;
for(var i=0;i<vA.length;i++) {
var dd=new Date(vA[i][0]);
var ddv=new Date(dd.getFullYear(),dd.getMonth(),dd.getDate()).valueOf();
if(ddv==cdv) {
dsh.appendRow(vA[i]);//Appends row with current date to dsh
ssh.deleteRow(i+2-d++);//Deletes ssh current row. Effectively making this a move instead of a copy
}
}
}
Sheet1 & 2 Before Running
Sheet1 & 2 After Running

Related

Google Sheets Script - Reference a specific cell in a row

I have a sheet where when I change a specific cell to "YES", I need a template sheet to be copied to a new version and named as per the value of a cell on the current row.
I'm having trouble working out how to get the value of the first cell in the row selected. This is what I have so far (I know this is wrong):
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var currentCell = sheet.getCurrentCell();
if (currentCell = "YES")
{
SpreadsheetApp.getActiveSpreadsheet().toast("New change control sheet added to workbook.","Change Control",15);
var sourceRow = ss.getActiveRange().getRowIndex();
var tabName = ss.getRange(cell,1).getValues();
ss.getSheetByName("CCTemplate").showSheet()
.activate();
ss.setActiveSheet(ss.getSheetByName('CCTemplate'), true);
ss.duplicateActiveSheet();
ss.setActiveSheet(ss.getSheetByName('CCTemplate'), true);
ss.getActiveSheet().hideSheet();
ss.setActiveSheet(ss.getSheetByName('Copy of CCTemplate'), true);
ss.getActiveSheet().setName("CC" & tabName);
}
}
Any ideas?
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()=='Your Sheet Name' && e.value=="YES") {
e.source.toast="New change control sheet added to workbook.","Change Control",15);
var tabName=sh.getRange(e.range.rowStart,1).getValue();
var tsh=e.source.getSheetByName('CCTemplate');
var csh=tsh.copyTo(e.source);
csh.setName('CC'+tabName);
}
}
You should avoid using activate in your scripts especially in simple triggers where you have to finish in 30 seconds. I think this code does the same thing that you intended for your code. One significant difference is that I use the information that comes in the event object that comes with the trigger. You should add the code Logger.log(JSON.stringify(e)) and then look at the logs you will see that there is a lot of information available to you which removes the need to run extra functions to get things like a spreadsheet.
Use event objects
onEdit offers among others the event objects range and value which are helpful to retrieve the range that has been edited and its value.
Also
When you want to a cell and compare it against a value, like in if (currentCell = "YES") - you need to retrive its value (either currentCell.getValue() or just event.value) and you need to use == instead of = for comparison.
Be careful with getValues() vs getValue(). The former gives you a 2D array and is not necessary if you want to retrieve the value of a single cell.
There is no need to set your sheet to active in order to change its name.
You can rewrite your code as following:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var currentCell = event.range;
var value = event.value;
if (value == "YES")
{
...
var sourceRow = range.getRowIndex();
var tabName = ss.getRange(sourceRow, 1).getValue();
...
ss.getSheetByName('Copy of CCTemplate').setName("CC" + tabName);
}
}

Adding a row to a named range

I have a named range in Google Sheets (A1:K14). All I'm trying to do is add a new row at the bottom of the named range. It seems like an easy task. The named range doesn't expand using this code and I don't get an error message. It does insert a new row outside of the named range, which is not what I'm trying to do. If I change to insertRowBefore (lastRow), the new blank row is inserted and the named range is expanded. I'm teaching myself GAS, so this is probably a simple mistake on my part
var sheet = SpreadsheetApp.getActiveSheet()
var Range = sheet.setActiveRange(range);
var data = Range.getValues();
Logger.log(range.getA1Notation());
var lastRow = SpreadsheetApp.getActiveSheet().getRange('DataRange').getNumRows();
SpreadsheetApp.getActive().insertRowAfter(lastRow);
return range;
Adding rows and/or columns to a namedRange
This function has the defaults setup to add one row.
//r is number of rows to add
//c is number of columns to add
function addRowAndColumnsToNamedRange(name,r,c) {
var name=name||'One';//default name
var r=r||1;//default number of rows to add
var c=c||0;//default number columns to add
var ss=SpreadsheetApp.getActive();
var nrgA=ss.getNamedRanges();
for(var i=0;i<nrgA.length;i++) {
if(nrgA[i].getName()==name) {
var nr=nrgA[i];
var h=nr.getRange().getHeight();
var w=nr.getRange().getWidth();
var sh=nr.getRange().getSheet();
var row=nr.getRange().getRow();
var col=nr.getRange().getColumn();
var rg=sh.getRange(row,col,h+r,w+c);
ss.setNamedRange(name,rg);
break;
}
}
}
Class NamedRange
Class Range
I think one of the approach can be to get that NamedRange and expand it explicitly.
Something like this:
Get that NamedRange using getNamedRanges() :
Set range of that NamedRange including new row using setRange(range)

How to append a timestamp after a copyTo has been executed on an onEdit trigger?

I'm using an onEdit function to trigger (among other things) a copyTo that moves a single row (consisting of two columns) to a new sheet (called CAC). Unrelated, the onEdit trigger is also adding a timestamp to a different sheet. I can't figure out how to add another timestamp to the CAC sheet in the column to the right of where the copyTo is landing. I'm assuming it's a combination of an offset and nesting something within the copyTo, but after some time of trying, can't figure it out! Thank you!
function onEdit(e) {
// DUE TODAY
{
e.source.toast('Processing...');
var sh=e.range.getSheet();
var name=sh.getName();
if(name=='Posting Tasks' && e.range.columnStart==1 && e.value) {
e.source.toast('Processing...');
var id=e.range.offset(0,2).getValue();
var tsh=e.source.getSheetByName('Database');
var idA=tsh.getRange(3,2,tsh.getLastRow()-2,1).getValues().map(function(r){return r[0]});
var row=idA.indexOf(id)+3;
var tsh=e.source.getSheetByName('Database').getRange(row,11).setValue(Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy"));
}
// Copy to CAC
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet()
if(ss.getActiveSheet() === 'Posting Tasks'){
//Get active cell
var cell = sheet.getActiveCell();
var cellCol = cell.getColumn();
var cellRow = cell.getRow();
var exportRange = sheet.getRange(cellRow,2,1,6);
//Select the paste destination
var pasteDestination = ss.getSheetByName('CAC');
var pasteEmptyBottomRow = pasteDestination.getLastRow() + 1;
//Copy the row to the new destination
exportRange.copyTo(pasteDestination.getRange(pasteEmptyBottomRow,3),
SpreadsheetApp.CopyPasteType.PASTE_VALUES);
// add timestamp
}
You want to put the timestamp to the right column of the column of the values copied by exportRange.copyTo(pasteDestination.getRange(pasteEmptyBottomRow,3), SpreadsheetApp.CopyPasteType.PASTE_VALUES).
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
In this modification, I used offset().
Modified script:
When your script is modified, it becomes as follows.
From:
exportRange.copyTo(pasteDestination.getRange(pasteEmptyBottomRow,3),
SpreadsheetApp.CopyPasteType.PASTE_VALUES);
To:
var timestamp = new Date();
var destRange = pasteDestination.getRange(pasteEmptyBottomRow,3);
exportRange.copyTo(destRange, SpreadsheetApp.CopyPasteType.PASTE_VALUES);
destRange.offset(0, exportRange.getNumColumns() - 1, exportRange.getNumRows()).setValue(timestamp);
When you run the modified script, the timestamp is put to the cells of the right column of the copied values.
Note:
If you want to put the timestamp to only one cell, please modify destRange.offset(0, exportRange.getNumColumns() - 1, exportRange.getNumRows()).setValue(timestamp); to destRange.offset(0, exportRange.getNumColumns() - 1).setValue(timestamp);.
In this case, as a sample, new Date() is used as the timestamp. So the date is put as the date object to the cell. If you want to see the time, please set the format of the cells with the date object.
Reference:
offset(rowOffset, columnOffset, numRows)
If I misunderstood your question and this was not the result you want, I apologize.

I need to automatically delete a row if cells on separate sheets match

I am trying to create a script that automatically deletes an entire row in sheet #1 if:
Cells in column B on sheet #2 are an exact match of cells in column A on sheet #1.
The row I want to delete is the row with the matching cell in sheet #1.
Here is a mock sheet:
https://docs.google.com/spreadsheets/d/1jjvzgTPlK7pPTRyaRkXKn3Pq8NbecJonHstDs-dJgAM/edit?usp=sharing
I am assuming that I will probably need a time-based trigger for this to work the way I need it to, but don't know where to start.
Any help is appreciated!
Try this:
function deleteMatches() {
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName('Sheet1');
var rg1=sh1.getRange(3,1,sh1.getLastRow()-2,1);
var vA1=rg1.getValues();
var sh2=ss.getSheetByName('Sheet2');
var rg2=sh2.getRange(3,2,sh2.getLastRow()-2,1);//Assuming data on sheet2 starts on same row
var vA2=rg2.getValues().map(function(r){return r[0];});
var d=0;
for(var i=0;i<vA1.length;i++) {
if(vA2.indexOf(vA1[i][0])!=-1) {
sh1.deleteRow(i+3-d++)
}
}
}

Copy a range and paste only rows with values into another sheet at the next blank row?

I'm trying to build off of what was solved here:
How do you copy a range and paste only rows with values into another sheet?
I want to do this with a bigger range (O1:X500 on the sheet named "RGDR") copying only the rows with values in them and then paste them in the new sheet ("ACTUALFUNC") in the next blank row.
The sheet is here: https://docs.google.com/spreadsheets/d/1vvXQxBGffwBAjbXKqx4N-ZFcX40wuV7gg9flb6STWtA/edit?usp=sharing
Below is the code I already tried. It only brings over the first column of data.
function copyRangeNoEmpties(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('RGDR');
var copyToSheet=ss.getSheetByName('ACTUALFUNC');
var copyFromRange=sh.getRange('O1:X500');
var vA=copyFromRange.getValues();
var oA=[];
for(var i=0;i<vA.length;i++)
{
if(vA[i][0])
{
oA.push([vA[i][0]]);
}
}
var copyToRange=copyToSheet.getRange(1,1,oA.length,1);
copyToRange.setValues(oA);
}
Looking to build a ongoing list of results by running this once daily. Any help or input will be greatly appreciated.
This will append your data to the next row on your destination sheet.
function copyRangeNoEmpties(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('RGDR');
var des=ss.getSheetByName('ACTUALFUNC');
var src=sh.getRange('O1:X500');
var vA=src.getValues();
for(var i=0;i<vA.length;i++) {
if(vA[i].join("")) {
des.appendRow(vA[i]);
}
}
}