I'm trying to change the value of a cell in a loop. All variables are defined as they should be but the status itself won't change and returns an undefined or Function not found error.
My code is the following
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2;
var numRows = 3;
var dataRange = sheet.getRange(startRow, 1, numRows, 8)
var data = dataRange.getValues();
for (i in data) {
var row = data[i];
var name = row[0];
var name2 = row[1];
var mother = row[2];
var father = row[3];
var sister = row[4];
var grandpa = row[5];
var mail = row[6];
var type = row[7];
var status = row[8];
var done = "DONE";
var not_done = "NOT DONE";
if (status = "TODO") {
//Do something...
status.setValue(done);
}
else {
//Do nothing...
}
}
Heading of the sheet are these:
Name Name2 Mother Father Sister Grandpa Mail Type Status
I tried adding a new loop
for (var i=0; i<numRows; i++) {
Utilities.sleep(500);
sheet.getRange(i+2, 9).setValue("DONE");
SpreadsheetApp.flush();
}
but this resulted in changing contents of other rows to and also an extra loop which shouldn't be necessary.
What (small) thing am I missing here?
That's because you are defining the numColumns to have 8 columns in total while the status field is 9th column (you started counting at 0). Hence it lies outside the range that you defined. In the 2nd one, it sorta worked because your range is 9.
The actual error is that status is a value not a cell object thus it has no "setValue". You should use the debugger which would have told you the exact line and problem. In the 2nd case you are using getRange correctly.also as another answer says you are using different column indexes (8 and 9 respectively)
The simplest way to replicate what you were trying to do is replace:
for (i in data) {
with:
for (var i=0; i<numRows; i++) {
and replace:
status.setValue(done);
with:
sheet.getRange(startRow + i, 9).setValue(done);
Related
Trying to hide rows in Google sheet after a task has been marked as closed and then writing a value "1" into a cell, so that the hidden rows can be ignored the next time the function runs.
The code fails on the line,
var status = range[i][5];
When I run the debugger, I can see it has read the correct value from the sheet. It is also showing the correct array of rows to hide.
Any help apprreciated, the rest of the code is below.
function HideClosed() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form responses 5");
var numRows = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
var startRow = 2;
var range = sheet.getRange(2, 1, numRows-startRow,lastCol).getValues(); //Get all values except the header rows
var rowsToHide = [];
for (var i = 2; i < numRows; i++){
var status = range[i][5]; // checks column 6 for status
var hidden = range[i][34]; // checks column 35 for hidden status
if (status == "Closed" && hidden != "1") { // checks for Closed jobs //that have not been hidden yet
rowsToHide.push(i+1);
}
}
var L = rowsToHide.length;
for (i = L ; i>0; i--){
sheet.hideRows(rowsToHide[i-1]);
sheet.getRange(rowsToHide[i][34]).setValue("1"); // writes 1 to column 35 after hiding //row
}
}
#Cooper - yeah, that worked, thanks.
It's very slow though, if it didn't time out, it took over 3 mins to hide 15 rows. From reading other threads on here, it seems to be a common enough problem..
Made a few changes to it today to try speed it up, but getting a "Cannot find function hide Rows error" now on the last line. Everything else looks good on the debugger.
function HideClosedWN() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form responses 5");
var numRows = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
var startRow = 2;
var range = sheet.getRange(2, 1, numRows-
startRow,lastCol).getValues(); //Get all values except the header rows
var rowsToHide = [];
for (var i=0; i<numRows-startRow; i++){
var status=range[i][5]; // checks column 6 for status
var hidden=range[i][34]; // checks column 35 for hidden status
if (status == "Closed" && hidden == 1){
rowsToHide.push(i+1);
}
}
sheet.getRange(2,1,rowsToHide.length,lastCol).hideRows(2,rowsToHide.length);
}
I think this might run:
function HideClosed()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form responses 5");
var numRows = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
var startRow = 2;
var range = sheet.getRange(2, 1, numRows-startRow,lastCol).getValues(); //Get all values except the header rows
var rowsToHide = [];
for (var i=0;i<numRows-startRow-1;i++)
{
var status=range[i][5]; // checks column 6 for status
var hidden=range[i][34]; // checks column 35 for hidden status
if (status=="Closed" && hidden!=1)
{
rowsToHide.push(i+1);
}
}
var L=rowsToHide.length;
for (i=rowsToHide.length-1; i>=0;i--)
{
sheet.hideRows(rowsToHide[i]);
sheet.getRange(rowsToHide[i],35).setValue(1); // writes 1 to column 35 after hiding //row
}
}
I have the following function that works to search for a column line by line and hides a row when it finds x. It works but is slow.
function SummaryViewGenerate() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var lastRow = sheet.getLastRow();
for( i=1 ; i<=lastRow ; i++) { // i <= lastRow
var status = sheet.getRange("K"+i).getValue();
if (status == "x") { // status == "x"
sheet.hideRows(i);
}
}
}
The problem is that it is super slow for my use. Any idea on how I can improve it. Someone mentioned on another thread about putting it into an array. Im still a coding newbie so any help in the right direction would be useful.
I think that it will be faster by getValues(). Reference is https://developers.google.com/apps-script/reference/spreadsheet/range#getValues()
Retrieve all data from spreadsheet using getValues. Data is put in 2D array.
Search "x" from the 2D array.
Sample is as follows.
function SummaryViewGenerate(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var array = sheet.getRange('k1').offset(0, 0, sheet.getLastRow(), 1).getValues();
for (var row in array) {
for (var col in array[row]) {
if(array[row][col] == "x") {
sheet.hideRows(row + 1); // (row + 1) is row number.
}
}
}
}
I have this script in Google Spreadsheet and it fetches all the rows marked "READY" just fine, then it sets the value in column "W"(23) to "SENT", and then I am trying to avoid fetching duplicates, by marking the column as "SENT" but then when I run the code again, it ignores the "SENT" that it just pasted? What is wrong here?
var ss = SpreadsheetApp.openById("12y85GmJ94s6k3213j2nGK8rFr0GOfd_Emfk8WHu_MUQ");
var stitchSheet = ss.getSheetByName("Sheet8");
var orderSheet = ss.getSheetByName("Sheet1");
var SENT = "SENT";
function getOrders() {
var range = orderSheet.getDataRange();
var orders = range.getValues();
for (var i = 1; i < orders.length; i++) {
var row = orders[i];
var status = row[1];
var order = row[4];
var name = row[5];
var system = row[22];
if(system != SENT){
if(status.toString() === 'READY'){
orderSheet.getRange(i,23).setValue(SENT);
stitchSheet.appendRow([order,name]);
}
}
}
}
Your code is fine, so there must be a logical error somewhere. I've noticed that you made var i in the for loop 1. I do not know if this is intentional or not, but the index of arrays pretty much always starts with 0 in most programming languages, which means that you'll start at row 2 of your sheet, not row 1.
Finding logical errors
To find logical errors you need to learn how to use the debugger console in the script editor.
Put breakpoints on the lines I mark with a star below:
var ss = SpreadsheetApp.openById("12y85GmJ94s6k3213j2nGK8rFr0GOfd_Emfk8WHu_MUQ");
var stitchSheet = ss.getSheetByName("Sheet8");
var orderSheet = ss.getSheetByName("Sheet1");
var SENT = "SENT";
function getOrders() {
var range = orderSheet.getDataRange();
* var orders = range.getValues();
for (var i = 1; i < orders.length; i++) {
* var row = orders[i];
var status = row[1];
var order = row[4];
var name = row[5];
* var system = row[22];
if(system != SENT){
if(status.toString() === 'READY'){
orderSheet.getRange(i,23).setValue(SENT);
stitchSheet.appendRow([order,name]);
}
}
}
}
Start the debugger and it will stop at the first breakpoint. Inspect what value range has. Expanding This should let you find orderSheet and SENT (since they are outside the function and should be in the scope). If not you've got a problem here.
Go to the next breakpoint and inspect orders, it should have an array of arrays now. You can inspect that you've got the right values, if not, skip forward to the next breakpoint and look at what row is.
Here is my code for the following, if I change the function getFilesByName() to getFileById() then it works perfectly fine, what is different and why is this not working as it should?
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 4; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 5)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var name = row[0];
var emailAddress = row[1]; // First column
var filename = DriveApp.getFilesByName(row[2]); // Second column
var message = row[3]; // Third column
var emailSent = row[4]; // Fourth column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "TEST" + name;
MailApp.sendEmail(emailAddress, subject, message, {
name: 'TEST',
attachments: [filename.getAs(MimeType.PDF)]
});
sheet.getRange(startRow + i, 5).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
The error is actually pretty explanatory, you have a File Iterator class (documentation) and not a File, you must apply the method next() to get the most recently updated file with that name, if you have more files with that name, you can use a combination o hasNext() and next() in a loop.
My code seems to be working properly, except for line 22, which is writing an "emailSent" value to line 20 of the Google Spreadsheet that the script runs against, instead of line 2 of that spreadsheet, which is the only row that has data. Any ideas?
function sendEmails2() {
//trying to adopt code from this tutorial https://developers.google.com/apps-script/articles/sending_emails
//-believe there is an issue with where I am declaring getRange to work-
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var lastRow = 40; // Last row of data to process
// Fetch the range of cells A1:B10002
var dataRange = sheet.getRange(startRow, 1, lastRow, 10)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
var i = data.length;
for (i in data) {
var row = data[i];
var emailAddress = row[7]; // raised an error at one point
var isEmailSent = row[9]; //
var partTimeApproved = row[0]
if (partTimeApproved != '') { // prevents sending emails to non-approved rows. for some reason = 'Y' doesn't work but !='' does //... or does it
if (isEmailSent == '') { // Prevents sending duplicates and sending emails to non-approved rows
var subject = "Email Subject Test";
var message = "Email body test"; // Standard string
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 10).setValue('emailSent'); //this didn't work: -replacing startRow + i with row-
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
}
I understand that while the code I am adopting from uses
getrange(startRow + i, 10).setValue('emailSent');
however, I do not understand how it could be finding row 20 and am not sure how to proceed in fixing it.
First
var i = data.length; <-- makes no sense
for (i in data) { <-- since you override i here
And I have no clue what data actually is. I am assuming it is an array of strings with numbers. AKA ['0','1']
So when you are expecting 2 and you are getting 20, it sounds like you are adding a string to a number
> 2 + "0"
"20"
convert it to a number.
> 2 + parseInt("0", 10)
2
So in the code:
getrange(startRow + parseInt(i, 10), 10).setValue('emailSent');