Google Sheets: Those rows are out of bounds error - google-apps-script

I am brand new to writing code and I am fumbling through this trying to come up with a spreadsheet that is fed info from a form. I have searched and searched for the answer to this problem for days but I cannot figure it out on my own without some help..so HELP! :)
What my script does it creates a copy of a sheet based on a trigger every night so that I have a record of form responses for each day. I want to to delete (not clear) all rows except the top 6 rows each time a new sheet is created so the form will add lines each time a response is given. I keep getting the Those rows are out of bounds. (line 17, file "DailyClear") when I try to run the script.
Here is what I've got
function dailyclear(e)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Today');
sheet.copyTo(ss)
var nusheet = ss.getSheetByName('Copy of Today')
var value = nusheet.getRange("B2").getCell(1,1).getValue()
SpreadsheetApp.setActiveSheet(nusheet)
Logger.log("Current index of sheet: %s", nusheet.getIndex())
ss.moveActiveSheet(2);
nusheet.setName(value);
//Clear "Today"
var lastrow = sheet.getLastRow()
sheet.deleteRows(7, lastrow-6)
//Set Date Value for "Today"
var dd = Utilities.formatDate(new Date(), "GMT-5", "MM/dd/yy");
sheet.getRange("B2").getCell(1,1).setValue(dd);
}
It will not allow me to delete the 7th row and retain rows 1-6 without throwing that error if the 7th row is blank and the only row that exists. If I start adding information from form responses in the cells and it starts creating rows and I run the script it throws up the error Sorry, it is not possible to delete all non-frozen rows. (line 17, file "DailyClear"). And on top of all that when a new sheet is created I have the 7th row clear ready for the first response from the form to fill and the form puts the first response of the day on row 8 and leaves 7 blank! This is driving me crazy...anyone recommend a good book for beginners before I go crazy? :( Thanks for any help I can get, here is a link to my sheet..
https://docs.google.com/spreadsheets/d/1NZxXjMptx6ldzL2CKk6OwJcq_heIv995ZGVeIE59xNc/edit?usp=sharing
Thank you to anyone who can help

As noted already, you cannot delete all non-frozen rows, so Row 7 will have to stay. Perhaps shrink it down and add a fill or some formatting so it just doesn't look like an empty row, and then since data is entered on row 8 anyway, change your script slightly to accomodate:
function dailyclear(e)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Today');
sheet.copyTo(ss)
var nusheet = ss.getSheetByName('Copy of Today')
var value = nusheet.getRange("B2").getCell(1,1).getValue()
SpreadsheetApp.setActiveSheet(nusheet)
Logger.log("Current index of sheet: %s", nusheet.getIndex())
ss.moveActiveSheet(2);
nusheet.setName(value);
//Clear "Today"
var lastrow = sheet.getLastRow()
sheet.deleteRows(8, lastrow-7);
//Set Date Value for "Today"
var dd = Utilities.formatDate(new Date(), "GMT-5", "MM/dd/yy");
sheet.getRange("B2").getCell(1,1).setValue(dd);
}

Related

Google Sheets - Script; getRange getLastRow copyTo

I'm rewriting a daily tracker that takes a row of data, and appends it to the last row on a second sheet for historical data.
var ss = SpreadsheetApp.getActiveSpreadsheet ();
var source = ss.getRange ("TODAY_TRACKER!P2:T2");
var destSheet = ss.getSheetByName("DATA");
var destRange = destSheet.getRange(destSheet.getLastRow()+1,1);
source.copyTo (destRange, {contentsOnly: true});
This just copies the row to the last row beginning at 1,1 on the data sheet.
I'm updating the tracking sheet to take the days numbers and make a table of weekly data; I want to append this row of data to the last row at a specific position on the same sheet.
var source = ss.getRange("NEW_TTRACKER!J3:O3");
var destRange = ss.getRange(ss.getLastRow(7,10,1,6)+1,1);
source.copyTo (destRange, {contentsOnly: true});
This obviously doesn't work, I was just taking a stab.
I'm attempting to copy the first row of data to column 7 row 10 for 1 row and 6 columns.
Then subsequent rows in the days following to go beneath the last.
Help is appreciated, thanks in advance.
It does not work since there's a syntax error on your destRange. First it's missing one opening parenthesis, second you're adding an incorrect syntax on the getRange function. The first parameter you used did not include some additional methods to pull the range and get the last row of the range. Also using getLastRow() will get the last row on the entire sheet so if you have any other data below the required range it will probably count that as well. So instead, we can approach this by getting values of data on the range and using length to determine which subarray has the last data and use that as reference to when moving to the next blank row.
See code below
function copyDataArray() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var destSheet = ss.getSheetByName("NEW_TTRACKER");
var source = destSheet.getRange("J3:O3");
//Define the position of the last available data on the weekly section
var lastrowonrange = destSheet.getRange("J7:J11").getValues().filter(String).length;
//Selects the area whare to past the data based on the last available data
var destRange = destSheet.getRange(lastrowonrange+7,10,1,6);
source.copyTo(destRange, {contentsOnly: true});
};
I'm able to run it properly that it appends data on the destRange.

Conditionally edit cells based of the value in cells in other rows - Google Sheet using Google Script

I've got limited knowledge of google script and I'm trying to get better every day. I'm trying to conditionally set the value of 2 cells based on the value in cells contained in other rows. I've got a sample sheet (here) with appointments on it. You'll also see the output desired on the output sheet.
When two or more appointments are taken by the same person based on his email address I want to write Yes in column Duplicate for every duplicate appointments but the most recent (based on Column E, that is the date when the appointment was created) and that are greater than the current date (if the appointment is already in the past no need to do anything). I also want to set the value of the column L to "Not Coming" which is a cell containing a data validation that I already automated on my main spreadsheet.
Here is the script that I already designed based on other questions answered here on stackoverflow. I'm not really familiar with indexes and how to proceed with them. The script runs without errors but nothing happens.
var currentDate = new Date()
// Master
var sheetMaster = ss.getSheets()[0];
var allValues=sheetMaster.getRange(2,1,sheetMaster.getLastRow()-1,sheetMaster.getLastColumn()).getValues();
var emailValues=sheetMaster.getRange(2,3,sheetMaster.getLastRow()-1,3).getValues();
var dateCreatedAtValues=sheetMaster.getRange(2,5,sheetMaster.getLastRow()-1,5).getValues();
var duplicateColumn=sheetMaster.getRange(2,11,sheetMaster.getLastRow()-1,11);
var eM=[];//emails
var dA=[];//dates
var eR=[];//entire rows
var dC=[];//duplicateColumn Yes or empty
function analyzeDuplicateEntries() {
for(var i=0;i<emailValues.length;i++) {
var idx=eM.indexOf(emailValues[i][0]);
if(idx==-1) {
eM.push(emailValues[i][0]);
dA.push(dateCreatedAtValues[i][0]);
eR.push(allValues[i]);
}
else if(new Date(dateCreatedAtValues[i][0]).valueOf() > new Date(dA[idx]).valueOf() && new Date(dateCreatedAtValues[i][0]).valueOf()> currentDate) {
duplicateColumn[i][0].setValue("Yes");
}
}
} ```
You are retrieving the wrong column and set the values to a range cell incorrectly
var mailValues=sheetMaster.getRange(2,3,sheetMaster.getLastRow()-1,3).getValues(); will return columns 3 to 5 (see documentation, while your emails are in column B, that is column 2.
Pay attention that the first parameter in getRange(row, column, numRows, numColumns) is the number of the columns to retrieve, rather than the last column
Mind that to use setValue on a range that contains more than one cell, you need to retrieve first the respective cell with getCell()
Take thereby into consideration that the cell indexes start with 1 (opposed to array indexes that start with 0`).
A simple (not optimal) way to rewrite your code would be:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var currentDate = new Date()
// Master
var sheetMaster = ss.getSheets()[0];
var allValues=sheetMaster.getRange(2,1,sheetMaster.getLastRow()-1,sheetMaster.getLastColumn()).getValues();
var emailValues=sheetMaster.getRange(2,2,sheetMaster.getLastRow()-1,1).getValues();
var dateCreatedAtValues=sheetMaster.getRange(2,5,sheetMaster.getLastRow()-1,1).getValues();
var duplicateColumn=sheetMaster.getRange(2,11,sheetMaster.getLastRow()-1,1);
var eM=[];//emails
var dA=[];//dates
var eR=[];//entire rows
var dC=[];//duplicateColumn Yes or empty
function analyzeDuplicateEntries() {
for(var i=0;i<emailValues.length;i++) {
var idx=eM.indexOf(emailValues[i][0]);
if(idx==-1) {
eM.push(emailValues[i][0]);
dA.push(dateCreatedAtValues[i][0]);
eR.push(allValues[i]);
}
else if(new Date(dateCreatedAtValues[i][0]).valueOf() > new Date(dA[idx]).valueOf() && new Date(dateCreatedAtValues[i][0]).valueOf()> currentDate) {
duplicateColumn.getCell(i+1, 1).setValue("Yes");
}
}
}

A script to find a section of a formula in a group of cells and replace it with input from the user

I've put together an attendance google sheet that pulls data from weekly attendance tabs to a master sheet with all the weeks together. So far the master sheet is set so that more weeks can be added by pressing a button by duplicating the first week of the master sheet and appending it to the last column of the sheet.
So what I need help with is in the cells of the new duplicated week find a portion of the formula, in the case would be the dates of the old week tab '9/21-9/25' (the full formula is ='9/14-9/18'!$E$5) and replace it with the new week inputted by the user with a prompt, example '9/28-10/2'.
This is the code I've come up with so far.
function newWeek() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lastCol = sheet.getLastColumn();
var rowCol = sheet.getLastRow();
var maxCols = sheet.getMaxColumns();
// Number of columns to duplicate//
var numCols = 15
//Selects the previous week//
var range = sheet.getRange(1, lastCol - 14, rowCol, 15);
//Inserts columns for next week//
sheet.insertColumnsAfter(lastCol, numCols);
//Copies previous weeks properties into new columns//
range.copyTo(sheet.getRange(1, lastCol + 1, rowCol, 15));
}
And if you think of an easier solution for what I am trying to do please let me know. It needs to be just a press of the button and enter the new dates and everything is created and pulled from the new week tab.
Class TextFinder can be used to search and replace within formulas using matchFormulaText() method:
Snippet:
range.createTextFinder('9/21-9/25')
.matchFormulaText(true)
.replaceAllWith('9/28-10/2')

Error only appears when running script in Apps Script Editor

I am trying to run a script that auto-populates the date in column F whenever data is entered or changed in column E in a spreadsheet with multiple sheets.
I currently have a script which was written for me based on what I described but I was getting an error code. I went back to my original question and explained that this script was needed to run on a single sheet within a spreadsheet with multiple sheets. He gave me some additional information but this was his last answer "yes, you will need to replace event.source.getActiveSheet() with something like "getsheetbyname". I have tried everything that is within my limited knowledge to work with what he gave me but I am still getting an error code no matter what I try.
Here is the area that is giving me the error.
var sheet = event.source.getsheetbyname();
Here is the error code I am receiving
TypeError: Cannot read property "source" from undefined. (line 2, file "Code")
I am aware that there needs to be the name of the sheet I am wanting the script to run on but I do not know how to code it to do so. The name of the sheet is "Juvenile weights"
The expected results should be when I add or change the data in column E it should auto-populate the current date into the adjacent cell in the adjacent column.
When I save the script and then run the script to make sure it's working, of course, it gives me the error code I described above. Then when I go back to that sheet after saving the script instead of auto-populating the date, now when I highlight a string of cells in a row it changes all the following cells to the same information I have in the first cell I started highlighting. Very odd!
The script + error code:
The code:
function onEdit(event) {
var sheet = event.source.getActiveSheet();
// note: actRng = the cell being updated
var actRng = event.source.getActiveRange();
var index = actRng.getRowIndex();
var cindex = actRng.getColumnIndex();
if (cindex == 5) { // 1 == Column A, 2 == Column B, 3 == Column C, etc.
var dateCol = sheet.getLastColumn();
var lastCell = sheet.getRange(index,dateCol);
var date = Utilities.formatDate(new Date(), "EST", "MMM-dd-yyyy");
lastCell.setValue("'" + date);
}
}
I believe this does the same thing:
function onEdit(e) {
var sheet = e.range.getSheet();
if (e.range.columnStart == 5) {
sheet.getRange(e.range.rowStart,sheet.getLastColumn()).setValue("'" + Utilities.formatDate(new Date(), "EST", "MMM-dd-yyyy HH:mm:ss"));
}
}
Is there a reason you aren't using SpreadsheetApp.getActiveSheet().getSheetByName("Juvenile weights");

ImportXML using Google Spreadsheets and Save Results Over-Time

I'm using ImportXML on Google Spreadsheets to scrape YouTube search results and capture the rankings of a video I'm tracking.
=IMPORTXML("https://www.youtube.com/results?search_query=control+theory&page=1"),"//div[#class='yt-lockup-byline']//a")
The scraping works well (and I get all the results for the first page). I then lookup the position of the YouTube results and save that in a cell.
However, the issue I'm having is when I'm trying to track that ranking over-time. Not sure how to do this but I'm looking for a way to run the =ImportXML function every day (is there a refresh command?) and save the result from that cell in a new row each time the function is run.
Any ideas?
importXML output is automatically updated (about every two hours), but you still need a script to save the past values somewhere: usually, on another sheet. Enter the following using Tools > Script Editor, adjusting the sheet names and the cell with the value of interest. Set it to run daily or weekly using Resources > Current project's triggers.
function storeValue() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1'); // where importXML is
var value = sheet.getRange("B3").getValue(); // where the cell of interest is
var sheet2 = ss.getSheetByName('Sheet2'); // where to store the data
var height = sheet2.getLastRow();
sheet2.insertRowAfter(height);
sheet2.getRange(height+1, 1, 1, 2).setValues([[new Date(), value]]);
}
At each run, the script appends two cells at the bottom of Sheet2: one with the timestamp (should be formatted as such), one with the value corresponding to that timestamp.
A version for storing a range of values such as B3:B7:
function storeValue() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var values = sheet.getRange("B3:B7").getValues()[0];
var sheet2 = ss.getSheetByName('Sheet2'); // where to store the data
var height = sheet2.getLastRow();
sheet2.insertRowAfter(height);
sheet2.getRange(height+1, 1, 1, 6).setValues([[new Date()].concat(values)]);
// setting 6 cells instead of 2 on the previous line
}