Why is GAS inputting a invalid range into a data validation? - google-apps-script

function DYNAMIC(){
var s = SpreadsheetApp.getActiveSpreadsheet(), ss = s.getSheetByName("Snippet Gen"),
dd = s.getSheetByName("dv snip"), column = 1, lastc = dd.getLastColumn(),
lastr = dd.getLastRow(), time = ss.getRange(2,1), name = ss.getRange(4,1),
time_v = time.getValue(), tp = dd.getRange(1,1,1,lastc),
nm = dd.getRange(2,column,lastr,1), match = dd.getRange(1,column).getValue();
var rule_tp = SpreadsheetApp.newDataValidation().requireValueInRange(tp,false).build();
time.setDataValidation(rule_tp);
for(; column < lastc; column++){
if(match = time_v){
var rule_nm = SpreadsheetApp.newDataValidation().requireValueInRange(nm,false).build();
name.setDataValidation(rule_nm);
}
}
}
Sheet 1: Snippet Gen
Sheet 2: dv snip
The result is the correct DV in A2 but a continuous Loading… DV in A4. And then when I go into the DV panel, the range is set as 'dv snip'!$A$2:$A$8 which is an invalid range. How do I set the range correctly?

if(match = time_v){ is an assignment not a comparison try this instead if(match == time_v){

You're most probably getting an invalid range because of this method:
nm = dd.getRange(2,column,lastr,1);
Please notice that the method getRange(row, column, numRows, numColumns) takes the number of rows as the third parameter, not the index of the last row in the range.
Because of this, here you are getting a range that:
Starts at row 2.
Its number of rows equals the index of the last row.
With these settings, the last row in this range doesn't exist. Therefore, you get an invalid range.
To fix this, you would have to substract the first row index to the third parameter in the method. One option would define the parameters and the method in this way:
var firstRow = 2;
var column = 1;
var numRows = dd.getLastRow() - firstRow + 1;
var numCols = dd.getLastColumn() - column + 1;
var nm = dd.getRange(firstRow, column, numRows, numCols);
Also, as Cooper said, you should use a comparison operator, not an assignment one in here:
if(match == time_v){
Reference:
getRange(row, column, numRows, numColumns)
Comparison operator
I hope this is of any help.

Related

How to add new row in Google sheet with todays date as top row, copying formulas from below row?

I am trying to create a new row automatically, every night in Google sheet with todays date as top row.
I have added the following script and set a daily trigger and it is working fine, but I have formulas in several columns and I wish to retain them in the newly added row. Can someone help me edit the script to do this? Thanks
`
function addNewRow() {
var spreadsheet = SpreadsheetApp.openById("1xwF-kM6KvOJYAfsmcDVBgO0yv6ZcFFMFvH33U7SzGtc");
var sheet = spreadsheet.getSheetByName("Attendance");
sheet.insertRowBefore(2);
var today = new Date();
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
var yyyy = today.getFullYear();
today = dd + '/' + mm + '/' + yyyy;
sheet.getRange(2,3).setValue(today);
`
Thank you for this. I was trying all day yesterday and came up with this to explicitly pus the formula to each row after the new row was inserted and also fill the date:
function addNewRow() {
var spreadsheet = SpreadsheetApp.openById("1xwF-kM6KvOJYAfsmcDVBgO0yv6ZcFFMFvH33U7SzGtc");
var sheet = spreadsheet.getSheetByName("Attendance");
sheet.insertRowBefore(2);
var today = new Date();
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
var yyyy = today.getFullYear();
var cell = sheet.getRange("B2");
cell.setFormula("=WEEKDAY(C2,1)");
var cell2 = sheet.getRange("A2");
cell2.setFormula('=TEXT(B2,"dddd")');
var cell2 = sheet.getRange("D2");
cell2.setFormula('=WEEKNUM(C2)');
today = dd + '/' + mm + '/' + yyyy;
sheet.getRange(2,3).setValue(today);
}
Try put this formula in A1, deleted all other values in A:C.
This will generate a set of 'week name', 'week no.' and 'date' in descending order start from TODAY to the 1st of November.
And since the data are generated by formula in A1, inserting rows in row 2 won't affect the result of formula.
You can than use the simple insert row everyday function to do the row inserting thing, with no need to care about the date and week values in A:C.
=ArrayFormula({
{"Day No.","Day","Date"};
{SPLIT(
LAMBDA(DATES,
CHOOSE(WEEKDAY(DATES),"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday")&";"
&WEEKDAY(DATES)&";"
&TEXT(DATES,"dd/mm/yyyy")
)(SORT(DATE(2022,11,SEQUENCE(DAY(TODAY()))),1,FALSE)),
";")}
})

append row to a specific column?

function dailyprofit() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Matt");
var profit = SpreadsheetApp.getActiveSheet().getRange('O2').getValue();
sheet.appendRow([,,,profit ]);
}
Hello, i'm attempting to use appendrow to put my variable into the last blank cell of row D, however appendRow does the entre row rather than just column D.
i would like the "profit" to be appended to row 362 rather than row 363 -> see example here
Thanks!
You can use this sample code to get the last row of Column D:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Matt");
var profit = SpreadsheetApp.getActiveSheet().getRange('O2').getValue();
var colValues = sheet.getRange("D1:D").getValues();
var count = colValues.filter(String).length
sheet.getRange(count+1,4).setValue(profit);
What it does?
Get all the column D values using sheet.getRange("D1:D").getValues()
Filter the array with string values and get its length/count. Empty cells will not be counted.
Increment the column D count by 1 and use Sheet.getRange(row,column) to get the cell below the non-empty cell in Column D. Use Range.setValue(value) to set the cell value.
Sample Output:
NOTE:
This will only work assuming you don't have an empty row in Column D.
If you have empty rows in your Column D, you might need to add few more offsets when incrementing the count.
Example:
I have 2 empty header rows (rows 1 and 2). Therefore, the offset of row count should be +3.
Sample Code:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Matt");
var profit = SpreadsheetApp.getActiveSheet().getRange('O2').getValue();
var colValues = sheet.getRange("D1:D").getValues();
var count = colValues.filter(String).length
sheet.getRange(count+3,4).setValue(profit);

How to find undefined or empty cells in a row with google script?

so as the title says I would like to find the empty or undefined cells in a row while iterating row until my lastrow. But it says "TypeError: Cannot read property "0" from undefined." Since it cant read undefined values and check it. You can see my code below. Thanks!
for (var row = startRow; row <= endRow; row++) {
var rangeA = "A" + row;
var rangeB = "H" + row;
var range = rangeA + ":" + rangeB;
var values = sheet1.getRange(range).getValues(); // get all data in one call
for ( var ct = 0; ct <= 7; ct++) {
if (values[ct][0]) = "")
runloop = false;
}
Cause:
Arrays are indexed by rows first and then columns. For example, A1:H1 contains 1 row and 8 columns or 1 inner array and 8 elements in that 1 inner array[[A1,B1,C1,D1,E1,F1,G1,H1]]. Therefore, values[1] will be undefined( since there's only 1 inner array whose index is 0). The script is looping through inner array instead of looping through elements of the inner array.
Solution:
Loop through the elements instead
Snippet:
if (values[0][ct] === "")

Script copies row data to another sheet, is only partially working

I have a script to move a row of data in an employee schedule spreadsheet (thanks to help from the Sheets reddit) it is working but has stopped finding one part of the data.
Spreadsheet here: https://docs.google.com/spreadsheets/d/10yLJ_NyFasGhlRt2LsXO2CC804Zf5JLvwUisgytQOhM/edit?usp=sharing
Once the Finished column 63 is set to "YES" it copies the data (only from the required columns), locates the employee's name based on whose week is marked "x" and moves them to the Finished Sheet.
The code used to work fully but now it isn't finding "x" or grabbing the employee's name.
I've had to update the column numbers in the script a few times as we've gotten more employees, it's possible I've broken it doing that.
(Any blank columns do have data in my real spreadsheet I've just left them blank here as it's not relevant to the script)
Would really appreciate any advice! Thank you!
[Full code in spreadsheet]
if (ecol == 63 && ssh.getName() == 'SCHEDULE' && rng.getValue() == 'YES') { //if Schedule!63 is YES
var data = []; //output data
var rowN = rng.getRow();
var rowV = ssh.getRange(rowN,1,1,63).getDisplayValues();
var row = rowV[0]; //get edited row
var colX = row.indexOf('x')+1; //find X
var offset = colX - ((colX-2) % 5 ) // offset to the first column
var emp = ssh.getRange(1,offset).getValue(); //get employee name
var dd = Utilities.formatDate(new Date(), "GMT+10", "dd/MM/yyyy") //generate date finished
data.push(row[1],row[2],row[3],dd,row[5],emp); //get row
dsh.appendRow(data); //move row
ssh.deleteRow(e.range.rowStart); //delete from schedule
}
}
I believe this var offset = colX - ((colX-2) % 5 ) // offset to the first column
should be this var offset = colX - ((colX+2) % 5 ) // offset to the first column
This is what's causing you to not find employees because the employees are in a merge group of cells which always puts it's value in the left most cell for horizontal merging.

How to remove duplicate rows while keeping only first row based on duplicate data in B & C columns. Rows to be checked sequentially

I have a google spreadsheet that is populated with end of day portfolio data in my 'portfolio history' sheet, so I require to delete rows where there is duplicate data in column B & C while keeping the first row with the oldest data.(eg duplicate data '123' in column B row 19,20,21 & '4567' column C row 19,20,21. I only require first entry in this case for row 19,rows 20, 21 to be deleted).The rows need to be checked sequentially for duplicates in column B & C. How would I do this? Thanks!!!
Image https://photos.app.goo.gl/7Ufowk4r7K9Gdpsw1
Try this:
function removeDupesInBAndC(){
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('portfolio history');
var rg=sh.getDataRange();
var vA=rg.getValues();
var dupesA=[];
var delA=[];
for(var i=0;i<vA.length;i++){
var s=vA[i][1].toString() + vA[i][2].toString();
var idx=dupesA.indexOf(s);
if(idx>-1){
delA.push(idx);
}else{
dupesA.push(s);
}
}
for(var i=delA.length-1;i>-1;i--){
sh.deleteRow(i+1);
}
}