Setting a specific cell on the active sheet - google-apps-script

I am attempting to set the value of a single cell on the active spread sheet. I know that I can uses .setValue to record a value to a single cell range. I want to get the range of a single cell than use .setValue to give it a specific value. I am using the following
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var testing_range = sheet.getRange("range_BOL_number");
logger.log("Rows: " + testing_range.getHeight() + " Columns: " + testing_range.getWidth());
var cell = testing_range.getCell(1, 0);
cell.setValue('999');
The problem is that when I try and run it, I get an error that says that the getCell call is out side of the range. The log entry tells me that testing_range is 2 rows by 1 column. Not sure what I am doing wrong as I copied the getCell code from the documentation.

its because getCell parameters are not zero based but one-based. you can see that from the example in the official docs. it uses getCell(1,1) to get the first cell from the example range:
https://developers.google.com/apps-script/reference/spreadsheet/range
personally i think it should be zero based as the parameters are not really "row" and "column" but a delta.

Related

Google Sheet Macro - how do I return a column number based on dynamic cell contents?

I have the following code as a starting point. I want to select the entire column where row 3 contains a specific date value (it will be the date of the previous Monday; I have a formula returning this date in cell E1).
function selectDate() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
ss.getRange(3,?,1,ss.getMaxColumns()).activate();
}
Basically, the getRange column value would be interpreted as something like: "Find the column number where the value in row 3 is equal to the value in cell E1".
Any ideas would be very helpful, even if it's using a totally different method to achieve the same thing. Thank you so much!
In your situation, how about the following sample script?
Sample script:
function selectDate() {
var sheet = SpreadsheetApp.getActiveSheet();
var searchValue = sheet.getRange("E1").getDisplayValue();
var res = sheet.getRange(3, 1, 1, sheet.getLastColumn()).createTextFinder(searchValue).matchEntireCell(true).findNext();
if (!res) return;
var column = res.getColumn();
sheet.getRange(1, column, sheet.getLastRow()).activate(); // Here, the found column is activated.
Browser.msgBox("Found column number is " + column); // Here, the found column number is shown in a dialog.
}
From your situation, I thought that getRange(3,?,1,ss.getMaxColumns()) in your script might be getRange(3, 1, 1, sheet.getLastColumn()).
When this script is run, row 3 is searched using the value of cell "E1". When the value is found, as a sample, the found column is activated and the column number is shown in a dialog. This is a sample. Please modify this for your actual situation.
Note:
If no column is selected, it is considered that the value of cell "E1" is not found in row 3. At that time, can you provide the detail of your Spreadsheet? By this, I would like to modify it.
Reference:
createTextFinder(findText) of Class Range

Using Row() within a formula with appendRow

So I'm pulling some data from GMail and adding a new row to a sheet that has a specific format. Name, Address, etc etc
On Column "P" I want to replicate the below:
=IF(NOT(ISBLANK($J3985)),"Replied", IF((TODAY()>=$O3985),"Late", "OK"))
However, I want to replace 3985 with Row(), for the row number that I'm appending, while I'm appending it. I've tried playing with: ADDRESS(row(),10) but this returns a string value that I can't seem to re-insert into a formula in a manner that works.
What I'm passing through in appendRow now:
var replied = "";
var later = x // a Date that's today + 6 weeks
var checkResult = `=IF(NOT(ISBLANK(` + replied + `)), "Replied", IF((TODAY()>=` + later + `), "Late", "OK"))`;
I want it so that I can populate the "responded" cell at a later point in the sheet and for this to still work. Would be keen to hear your suggestions for the same.
If you use appendRow:
=IF(NOT(ISBLANK(INDIRECT("RC[-6]",FALSE))),"Replied", IF((TODAY()>=INDIRECT("RC[-1]",FALSE)),"Late", "OK"))
If you use setFormulaR1C1:
Method A
Putting the row number directly with template literal
Method B
You could use setFormulaR1C1(formula)
'=IF(NOT(ISBLANK(RC[-6])), "Replied", IF((TODAY()>=RC[-1]), "Late", "OK"))';

Copy filtered data to another sheet but creates a blank row if it met a condition

For example, I have this data,
I want to filter the data which is "USA" and copy it to another sheet but I have to creates a blank row if it met a condition. For example like this
Is it possible?
I have also tried
IF(AND(F2=FALSE, NOT(ISBLANK(F2))), "", INDEX(QUERY('Sheet 1'!A2:E, "Select A where A contains '"&"USA"&"'"),COUNTIF($F$2:F2,TRUE),1))
But it didn't work as I expected
Here is a formula version:
=ArrayFormula(
array_constrain(
sortn(
filter(
{if(A:A="USA",A:A,),if(A:A="USA",B:B,),A:A="USA",
if(A:A="USA",row(A:A),iferror(vlookup(row(A:A),if(A:A="USA",row(A:A),),1,true),0)+1)},
A:A<>""),
1000,2,4,1),
1000,3)
)
The reason for the long formula is mainly finding a way to get just one row to replace one or more rows that don't start with USA. The basis of the formula is to do a lookup for non-USA rows to get the row number of the most recent USA row. All of the non-USA rows in the same block then have the same row number and can be discarded (apart from the first) using Sortn.
I have added an extra non-USA row at the beginning to check that this edge case works and falls through to the Iferror clause.
Since you provided Google Apps Script as tag, I assume you are open to script answers? If so, then I'll provide this code below. Is this what you are looking for?
function copyUSA() {
var sheetSrc = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var sheetDst = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var rowSrc = sheetSrc.getLastRow();
var values = sheetSrc.getRange("A2:A" + rowSrc).getValues().flat();
values.forEach(function (value, index){
var rowDst = sheetDst.getLastRow() + 1;
if(value == "USA"){
// If USA, copy then replace third column with TRUE
var row = index + 2;
sheetSrc.getRange(row + ":" + row).copyTo(sheetDst.getRange(rowDst + ":" + rowDst));
sheetDst.getRange("C" + rowDst).setValue("TRUE");
}
else{
// If not, set third column to FALSE
sheetDst.getRange("C" + rowDst).setValue("FALSE");
}
});
}
Sheet1:
Sheet2:
My assumptions were based from your formula. These are:
I assumed that you add blank when it is not USA. Thus having 2 blanks on the output
If USA, 3rd column is TRUE, else, FALSE with blank data
Based on your formula, it seems your data starts at A2, thus I adjust the code too.
You are also getting the 4th and 5th column on your formula but since you didn't show it in your post, I can't assume any values for it.
If the answer isn't the one you are looking for, I apologize.

Is there a way to display values different based on date?

I'm trying to grab data vertically and display it horizontally with a column in between each value.
Here is example data:
Here is what I'm trying to get it to do:
I've tried exhausting everything I currently know to figure this out but I can't seem to get it and I believe it's an easy problem to fix. I'm just not having much luck with my keywords in google.
ps: just noticed I had some columns hidden still. In this case lets pretend the columns in examples are A/B/C/D/E.
Summarizing identical dates on multiple rows into separate columns on the same row
I don't completely understand how you went from example 1 to example 2 but it is clear that you want to summarize multiple rows with the same date into multiple columns on one row and that's what this function is an example of.
I'm guessing that once you provide a better explanation of what your trying to accomplish and how it's supposed to work then you may get some answers that are a lot easier to figure out.
Anyway I offer this solution as a possibility that you can start with if you like. I'm using a key/value object to keep track of the number of identical dates and if the method dObj.hasOwnProperty() returns false then it also helps to identify new dates.
The Code:
function condenseDates(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('sheet name');//you need to change this for the appropriate sheet name
var rg=sh.getDataRange();//get all data values including headers
var vA=rg.getValues();
var dObj={};//data object which is used to identify new new dates and keep track of the run columns for identical dates.
var d=0;//delete counter
for(var i=1;i<vA.length;i++){
if(dObj.hasOwnProperty(vA[i][0])) {//if it does not have this property then it is a new date
dObj[vA[i][0]]=Number(dObj[vA[i][0]])+1;//if it does have this property then increment the DObj value which keeps track of the run column it will go into
var rg=sh.getRange(1,2 + Number(dObj[vA[i][0]]));//this is the header column cell for this dObj column
if(rg.isBlank()){//if it is blank then write a new one
rg.setValue('Run' + dObj[vA[i][0]]);
}
sh.getRange(Number(dObj.currentRow),2 + Number(dObj[vA[i][0]])).setValue(vA[i][1]);//put value for this line in the appropriate column in the currentRow
sh.deleteRow(i-d+1);//delete this line
d++;//increment the delete counter
}else{//it is a new date
dObj[vA[i][0]]=1;
dObj['currentRow']=i-d+1;//Current Data Row
var rg=sh.getRange(1,3);
if(rg.isBlank()){//if header has no label in the first run column then write it
rg.setValue('Run' + 1);
}
sh.getRange(Number(dObj.currentRow),2 + Number(dObj[vA[i][0]])).setValue(vA[i][1]);//write data in the appropriate column in this case it is always column3
}
}
sh.deleteColumn(2);
}
The Example Spreadsheet before running the script:
The Example Spreadsheet after running the script:
The value in column 2 for each consecutive identical date is placed in the next column on the first row in which that date appears. At the end column2 is deleted.
Javascript Object Reference
Google Apps Script Documentation
SpreadsheetApp Documentation
I played around with this and this version doesn't required additional identical dates to be consecutive. It create a unique currentRow for each date and that current row is used for all remaining identical dates even if they occur after other remaining dates. ie the dates don't have to be sorted.
function condenseDates(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('36');//you need to change this for the appropriate sheet name
var rg=sh.getDataRange();//get all data values including headers
var vA=rg.getValues();
var dObj={};//data object which is used to identify new new dates and keep track of the run columns for identical dates.
var d=0;//delete counter
for(var i=1;i<vA.length;i++){
if(dObj.hasOwnProperty(vA[i][0])) {//if it does not have this property then it is a new date
dObj[vA[i][0]]=Number(dObj[vA[i][0]])+1;//if it does have this property then increment the DObj value which keeps track of the run column it will go into
var rg=sh.getRange(1,2 + Number(dObj[vA[i][0]]));//this is the header column cell for this dObj column
if(rg.isBlank()){//if it is blank then write a new one
rg.setValue('Run' + dObj[vA[i][0]]);
}
sh.getRange(Number(dObj[vA[i][0].toString()+'currentRow']),2 + Number(dObj[vA[i][0]])).setValue(vA[i][1]);//put value for this line in the appropriate column in the currentRow
sh.deleteRow(i-d+1);//delete this line
d++;//increment the delete counter
}else{//it is a new date
dObj[vA[i][0]]=1;
dObj[vA[i][0].toString()+'currentRow']=i-d+1;//A unique Current Data Row for each date when additional identical dates will expand into additional columns.
var rg=sh.getRange(1,3);
if(rg.isBlank()){//if header has no label in the first run column then write it
rg.setValue('Run' + 1);
}
sh.getRange(Number(dObj[vA[i][0].toString()+'currentRow']),2 + Number(dObj[vA[i][0]])).setValue(vA[i][1]);//write data in the appropriate column in this case it is always column3
}
}
sh.deleteColumn(2);
}

Paste as Value when cell is empty (google-apps-script)

Currently I am using the following script:
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange('Sheet1!C16:C16');
source.copyTo(ss.getRange('Sheet2!A1'), {contentsOnly: true});
source.clear();
}
However I want to append the pasted data in sheet2 with new data that is generated weekly.
So once a week sheet1 is updated and the value in 'Sheet1!C16' will change. I want to append this in 'Sheet2!A2'. and so forth.
So how can I edit this script to make sure the new value is copied in the next empty cell (so when 'Sheet2!A1' has a value get the new value from 'Sheet1!C16' and copy it to 'Sheet2!A2'. And when 'Sheet2!A1'is has a value, copy the new value from 'Sheet1!C16' to 'Sheet2!A3'
I need to to this for all weeks of the year (so just to be safe 53 weeks)
Thnx in advance!
It depends, you can do a few things.
The first one is the easiest, however there is a condition. If each week you copy to cell A1 → A2 → A3 and just keep going down, then each week, that data that you copy over is always the lowest. So for example if you wish to copy data to cell A3 that means that the last row to have any data in any column is row 2. That way all you need to do is get the range like this: ss.getRange(ss.getLastRow() + 1, 1)
The other method is to use PropertiesService to store which row is the last one in use. On script run, get that value
var nextRow = PropertiesService.getScriptProperties().getProperty('property we added before')
and then when you get the target range you use
ss.getRange(nextRow, 1)
PropertiesService.getScriptProperties().setProperty('property we added before', nextRow + 1)
that way you get the next row each time and you update the property for the next time you wish to run. With this you also need to keep in mind that you might want to reset the counter after the year.