Delete cells based on date but leave formatting - google-apps-script

I got this script from "Delete Cells Based On Date" question that was asked. It deletes the actual row which removes all the formatting and variables. Is there a way to have it just remove the values?
Delete Cells Based on Date
This is the code:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Field1");
var datarange = sheet.getDataRange();
var lastrow = datarange.getLastRow();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();
var oneweekago = new Date();
oneweekago.setDate(currentDate.getDate() - 1);
for (i=lastrow;i>=2;i--) {
var tempdate = values[i-1][0];// arrays are 0 indexed so row1 = values[0]
and col3 = [2]
if(tempdate < oneweekago)
{
sheet.deleteRow(i);
}
}
}

What you're looking for is .clearContent() rather than deleteRow. This will only clear the contents of the cell, but leave all formatting in tact. Here's the Class Range documentation, it's really useful when looking at what you can do with a specific range in a sheet.
Now to get this to work the way you want, you'll have to use 2 for statements, one to get the row number (i), and the other to get the column number (j), which you can then use in the .getRange to run the .clearContent() on.
function clearOldRecords() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Field1");
var dataRange = sheet.getDataRange();
var lastRow = dataRange.getLastRow();
var data = dataRange.getValues();
var currentDate = new Date();
var oneWeekAgo = new Date();
oneWeekAgo.setDate(currentDate.getDate() - 7);
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].length; j++) {
var tempDate= data[i][0]; //column number is indexed from 0, change accordingly to your data
//if start date column is older than 7 days, clear the content of the row
if (tempDate!= "" && tempDate < oneWeekAgo) {
sheet.getRange(i+1,j+1).clearContent();
}
}
}
}
So, to explain this further, these are the notable changes I've made to your script.
Date subtractions are worked out in days, therefore doing a -1 will only take 1 day off of the date. You need a week so I have changed this to -7:
oneWeekAgo.setDate(currentDate.getDate() - 7);
The script also no longer scans the last row of the sheet, this could impact performance if the sheet is huge, but on your normal day-to-day sheet this shouldn't be an issue.
As you can see below, for loop for i gets all of the row numbers, and for loop j can be used for the column numbers, as you can see in the getRange() when trying to clear the contents:
sheet.getRange(i+1,j+1).clearContent();
Note: this may leave pretty huge gaps in your data if it's not sorted by date, you could add something like this to sort it afterwards (put this outside of the FOR loops):
sheet.getRange('A1:Z').sort({column: 2, ascending: false}) //change column number accordingly, this is NOT indexed from 0

Related

Google scripts - issue with string vs cell as function parameter

I'm learning Google script as I go along and came across an issue that I could not find a solution for.
I have a function that takes in several several strings and one cell as params.
I assume passing a cell is not same as passing its value (string too btw)
Please find attached code:
//return id assigned to data(cell) sheetname
function findInColumn(column, data, colName, sheetname) {
/*
data = cell (cell value is 'bag_backpack.png') does not work
var range = SpreadsheetApp.getActiveRange();
var col = range.getColumn();
var row = range.getRow();
var range2 = SpreadsheetApp.getActiveSheet().getRange(row,col+1);
data = range2.getValue(); (cell value is 'bag_backpack.png') <---fail too
data = 'bag_backpack.png'; <---works
*/
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetname);
var column = sheet.getRange(column + ":" + column); // like A:A
var values = [];
for (var index = 0; index < column.getValues().length; index++) {
values.push(column.getValues()[index][0])
}
var colIndex = getByName(colName, sheetname);
var rowIndex = values.indexOf(data);
//grab id value of data
var range = sheet.getRange(rowIndex+1,colIndex+1);
var data = range.getValue();
return data
}
While I value and need your feedback I kindly request your bear in mind I'm a novice at best and I've spend several hours searching before asking here.
Thank you for your help.
Edit: bag_backpack.png is the content of a cell I'm searching in a column to get the row number of said cell.
var rowIndex = values.indexOf(data);
Returns the index I need.
However... if I feed a cell to the function instead of a string like a cell elsewhere with bag_backpack.png as its content or even derive said value from it:
var range = SpreadsheetApp.getActiveRange();
var col = range.getColumn();
var row = range.getRow();
var range2 = SpreadsheetApp.getActiveSheet().getRange(row,col+1);
data = range2.getValue(); (cell value is 'bag_backpack.png') <---fail too
In said case:
var rowIndex = values.indexOf(data);
gives out -1 instead of index desired.
Most of what you have doesn't make sense to me. I'm guessing that this is what you want. Since I can't figure out what you want, perhaps you can tell me what I missed.
function findInColumn(column,sheetname) {
var sh=SpreadsheetApp.getActive().getSheetByName(sheetname);
var rg=sh.getRange(column + ":" + column); /
var vA=rg.getValues();
var values = [];
for (var i=0;i<vA.length; i++) {
values.push(vA[i][0]);
}
return values
}
I want to thank everyone for taking the time to reply.
the issue was NOT with the code but with some of the first filename having uppercase in the id,name sheet while the binder sheet it did not.(at least 5 hours on Tent.png/tent.png)
I'm attaching a link to my finished work in hopes it benefits anyone.
https://docs.google.com/spreadsheets/d/1jCy1I4r6PeY3kUWrhNno2XO18Jghq6_b1kyN3AflidM/edit?usp=sharing

Delete a row in Google Sheets when a date has passed

I have a spreadsheet that I would like to autosort based on date, delete duplicate rows, and delete rows if the date listed has passed. I have the autosort and deleting duplicates, I just need help with deleting rows based on the date. It will delete all rows except row # 2, regardless of date.
So far I have:
function deleteRow1() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow()-1; // Number of rows to process
var dataRange = sheet.getRange(startRow, 2, numRows);
var data = dataRange.getValues();
for (i = 0; i < data.length; i++) {
var row = data[i];
var date = new Date();
var sheetDate = new Date(row);
var Sdate = Utilities.formatDate(date, 'EST-0500', 'MM:dd:yyyy')
var SsheetDate = Utilities.formatDate(sheetDate, 'EST-0500', 'MM:dd:yyyy')
if (Sdate > SsheetDate) {
sheet.deleteRow(i + 2)
}
}
}
So here is about what it could look like, I think. I changed as little as I could about your routine, focusing on the parts that seemed like they were troubling.
In particular, dates are compared to dates, with times removed/equated. Also, it bothered me to repeatedly construct today, so I took that outside the loop.
Also, I worked from the bottom up to make sure deletions did not affect which row to consider next.
function deleteRow1() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow()-1; // Number of rows to process
var dataRange = sheet.getRange(startRow, 2, numRows);
var data = dataRange.getValues();
var today = new Date();
today.setHours(0,0,0,0);
for (i = data.length-1; i > -1; i--) {
var row = data[i];
var sheetDate = new Date(row);
sheetDate.setHours(0,0,0,0);
if (today > sheetDate) {
sheet.deleteRow(i + 2)
}
}
}
It might be a nice touch to change i+2 to startRow+i.

Delete row if column has date older than one month

I found this code from https://stackoverflow.com/users/6656050/jeremy-kahan and edited it a little. I need my sheet to delete any row when the entry in column L is older than one month, but keep the row if the cell in column L is empty i'll need some guidance. On request I can provide a copy of my sheet and show examples. It might seem easy it others but I feel at a disadvantage only being 16 and just learning java.
function DeleteOldEntries() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");//assumes Sheet 1 is the name of the sheet
var datarange = sheet.getDataRange();
var lastrow = datarange.getLastRow();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();//today
var monthOld = Date.now() + -30*24*3600*1000;
for (i=lastrow;i>=3;i--) {
var tempDate = values[i-1][11];// arrays are 0 indexed so row1 = values[0] and col12 = [11]
if (tempDate <= (monthOld))
{
sheet.deleteRow(i);
}
}
I'm going to provide some help, even though I'm going to get chastised for it. In the future, do some research, try to understand the code and make the code work for your purpose. If you can't, and Google doesn't help, THEN come on and ask a CLEAR question with all of the details. Most of the top dogs on here won't even look at your question if all of that isn't done. Also, be sure to use the correct tags on your questions. It won't even show up to the correct people without them.
Now to your answer:
You want to delete a row if the date in column L is > 30 days in the past. The code you provided is looking at column C for the date. So that is the first thing that needs to be changed. Second, the conditional if ((tempDate!=NaN) && (tempDate <= currentDate)) is checking to see if the cell is empty (NaN), or if the date is <= TODAY, NOT today - 30. So, you need a way to calculate what today - 30 days is: var monthOld = Date.now() + -30*24*3600*1000;, then you can compare that to the date in column L.
If you make those two changes, you get:
function DeleteOldEntries() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Live Events");//assumes Live Events is the name of the sheet
var datarange = sheet.getDataRange();
var lastrow = datarange.getLastRow();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();//today
var monthOld = Date.now() + -30*24*3600*1000;
for (i=lastrow;i>=3;i--) {
var tempDate = values[i-1][11];// arrays are 0 indexed so row1 =
values[0] and col12 = [11]
if ((tempDate!=NaN) && (tempDate <= (monthOld)))
{
sheet.deleteRow(i);
}
}
}
This should do what you want. If you have any further questions, let me know. I'm happy to help.
function DeleteOldEntries() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");//assumes Sheet 1 is the name of the sheet
var datarange = sheet.getDataRange();
var lastrow = datarange.getLastRow();
var values = datarange.getValues();// get all data in a 2D array
var currentDate = new Date();//today
var monthOld = Date.now() + -30*24*3600*1000; //to change amount of days adjust "30"
for (i=lastrow;i>=3;i--) {
var tempDate = values[i-1][11];// arrays are 0 indexed so row1 = values[0] and col12 = [11]
if ((tempDate!="") && (tempDate <= (monthOld)))
{
sheet.deleteRow(i);
}
}
}

move a row in google spreadsheet based on todays date

I'm trying to move a row of data from one sheet to another in the same spreadsheet based on a value of today's date.
In column "A", I have a date. I want to move the row if the date entered in column "A" is older than today's date. (it's a flight schedule for aircraft and I want to move flights that have already occured onto a sheet called "Past Flights".) The name of the active sheet is "Flight Schedule".
After the row is moved, I want it to delete off the "Flight Schedule" sheet. I know where to add scripts, but have no idea how to make this happen.
Here is what I have tried. I think on line "If (data.link >1..." data.link isn't the right one to use. But I can't find something for indicating older than todays date.
function approveRequests() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
if (sheetName == "Flight Shedule") {
var range = sheet.getActiveRange(),
startRow = range.getRowIndex(),
numRows = range.getNumRows(),
numCols = range.getNumColumns()
if (numCols == 9) {
if (data.length > 1) {
var values = range.getValues(),
nextSheet = ss.getSheetByName("Past Flight"),
lastRow = nextSheet.getLastRow();
nextSheet.getRange(lastRow+1,1,numRows,3).setValues(values);
sheet.deleteRows(startRow,numRows);
}
}
}
}
Any help would be huge!
Thanks!
Ok, I will go in with some general tips based on your current code first.
In your function you do a sheet = ss.getActiveSheet() which is redundant because you already have SpreadsheetApp.getActiveSpreadsheet().Also I would recommend to avoid this
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
in favour of this:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var sheetName = sheet.getName();
var data = sheet.getDataRange().getValues();
which is much more easy to read and change without making mistakes.
data.length has nothing to do with current date, it will simply be the length of the array. So if you select 1 row of data, it will be 1, if you select 2 rows it will be 2 etc. .getValues() will return an array where data[row][col]. What you are looking for is getting the value of the flight time, converting it into a date object (not a google specific thing, just general javascript). Then use var now = new Date() and compare the two.
I would also recommend to re-think your if statements. There are a lot of better ways to grab the row data than selecting the row manually and then running the function. You can save a lot of lines of code should you decide to actually make this run automatically, because as it is, it will run only when called manually.
This sample is working:
function approveRequests() {
// Initialising
var ss = SpreadsheetApp.getActiveSpreadsheet();
var scheduleSheet = ss.getSheetByName("Flight Shedule");
var pastSheet = ss.getSheetByName("Past Flight");
var lastColumn = scheduleSheet.getLastColumn();
// Check all values from your "Flight Schedule" sheet
for(var i = scheduleSheet.getLastRow(); i > 0; i--){
// Check if the value is a valid date
var dateCell = scheduleSheet.getRange(i, 1).getValue();
if(isValidDate(dateCell)){
var today = new Date();
var test = new Date(dateCell);
// If the value is a valid date and is a past date, we remove it from the sheet to paste on the other sheet
if(test < today){
var rangeToMove = scheduleSheet.getRange(i, 1, 1, scheduleSheet.getLastColumn()).getValues();
pastSheet.getRange(pastSheet.getLastRow() + 1, 1, 1, scheduleSheet.getLastColumn()).setValues(rangeToMove);
scheduleSheet.deleteRow(i);
}
}
}
}
// Check is a valid date
function isValidDate(value) {
var dateWrapper = new Date(value);
return !isNaN(dateWrapper.getDate());
}
So yes, It's not the optimized solution (cause of the use of several sheet.getRange() method), but it's working and allowing to have a clear code.

More efficient way too look up the last row in a specific column?

I'm writing an app that will import columns from one sheet to another. The .getLastRow method will only apply to the whole sheet, but can't be used to get last row of a column. There is an issue open requesting this feature.
I've written something with the help of the 2D Array library from the folks over at Google Script Examples: https://sites.google.com/site/scriptsexamples/custom-methods/2d-arrays-library
I've gotten a working version that finds the last row in a specific column, but I suspect it's rather ineffecient.
function readRows() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var numRows = sheet.getLastRow();
var numColumns = sheet.getLastColumn();
var data = sheet.getRange(1, 1, numRows, numColumns).getValues();
//Get the Headers, Search for a value of the headers and index
var headerArray = sheet.getRange(1, 1, 1, numColumns).getValues();
var flip = ArrayLib.transpose(headerArray)
var search = "Greens";
var whereGreen = ArrayLib.indexOf(flip, 0, search);
//Get the value of the column with matching headers, and looks up Column length.
var values = sheet.getRange(1, whereGreen +1, numRows, 1).getValues();
//finds last value, makes string
for(; values[numRows - 1] == "" && numRows > 0; numRows--) {}
var lastValue = values[numRows - 1].toString();
//Indexes where the string is, which gives the value -1 of the last row in column.
var lastRowCol = ArrayLib.indexOf(values, 0, lastValue);
Logger.log(lastRowCol +1);
}
Can anyone help me get to a streamlined version? I'm sure JavaScript could do it, but I'm rather light on my knowledge in that department.
The code can be made more efficient by reducing the number of calls to the spreadsheet service. The following code is much faster:
function readRows() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = sheet.getDataRange().getValues();
var numRows = data.length;
//Get the Headers, Search for a value of the headers and index
var headerRow = data[0];
var search = "Greens";
var whereGreen = headerRow.indexOf(search);
//finds last value, makes string
while( data[numRows - 1][whereGreen] == "" && numRows > 0 ) {
numRows--;
}
var lastValue = data[numRows - 1][whereGreen].toString();
Logger.log( 'Last row: '+ numRows );
Logger.log( 'Last value: '+ lastValue );
// Not clear what this does, what more information is needed?
//Indexes where the string is, which gives the value -1 of the last row in column.
//var lastRowCol = ArrayLib.indexOf(values, 0, lastValue);
// Logger.log(lastRowCol +1);
}
I replaced the for loop with a while loop, but that should not make much difference in efficiency, makes it a bit more readable.
In terms of efficiency, this is about as close as you get to efficient, in my opinion. In terms of a cleaner solution, I can't seem to think of one right now. Will update if I think of anything.