Google Apps Script - Hide Rows Older Than a Month - google-apps-script

I found this solution but am struggling to get it to work on my sheet.
The user who submitted that question had 3 header rows and wanted the script to only work on row 4 and down. I have 1 header, and as such need the script to work on row 2 and down.
I've got it leaving row 1 alone - but it ONLY hides rows 2 and 3. I can't figure out where I'm going wrong.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuItems=[{name: 'HideRows', functionName: 'hideRows'}];
ss.addMenu('Hide Rows', menuItems);
};
function hideRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Responses");
var v = s.getRange("B:B").getValues();
var today = new Date();
var m = today.getMonth();
for(var i=3;i<v.length;i++)
if(v[i][0]=="" || v[i][0].getMonth()>=m) break;
if(i>1) s.hideRows(2,i-1)
};
ETA: Here's a link to my sheet/script: https://docs.google.com/spreadsheets/d/1PkB1_hlJoI-iFYTAN8to_ES9R8QyUxEgPsWtSTUmj8U/edit?usp=sharing

function hideRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Responses');
// start range from B2 skipping header
// join() + split(',') converts 2D array into plain array
// filter(Boolean) skips all the blank cells in column
var v = s.getRange('B2:B').getValues().join().split(',').filter(Boolean);
// today in milliseconds for date comparison
var today = new Date().getTime();
// one month in milliseconds
var oneMonth = 2629746000;
Logger.log(v.length);
for (var i=0;i<v.length;i++) {
// Date Object from cell in B2:B in milliseconds
var vDate = new Date(v[i]).getTime();
// exit for loop when first date less than one month is found
if (today - vDate <= oneMonth) {
break;
}
}
Logger.log(i+1);
s.hideRows(2, i);
}

You have a syntax error on your for loop as well as the if statements. There should be {} the code to be worked on when in these portions. Then there is an error in your logic. The month of October in row 2 is greater than the current month, February. So you may want to first compare Years for the highest year and then compare months:
function hideRows() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("Responses");
var v = s.getRange("B:B").getValues();
var today = new Date();
var m = today.getMonth();
var y = today.getYear();
for(var i=3;i<v.length;i++){
if(v[i][0] === "" || v[i][0].getYear() >= y){
if(v[i][0].getMonth() >= m) {
var stophere = 0;
break;
}
}
}
if(i>1) {
s.hideRows(2,i-1);
}
};

function onOpen(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Responses');
var today= new Date();
var today=today.setDate(today.getDate()-30); //minus 30 days
for ( var i = sheet.getLastRow(); i >= 2 ; i-- ) {
var filter = sheet.getRange(i, 2).getValue();//Evaluates Column B
if ( filter.valueOf() < today.valueOf()) {
sheet.hideRows(i); }
}
}

Related

Converting my script to use getRangeData instead of using an iterative loop (GoogleAppScript)

I am having issues converting my last script to work with getDataRange. I got some help converting my original functions, seen below:
function twentyDKP() {
alertBox20DKP()
}
function alertBox20DKP() {
var sh=SpreadsheetApp.getUi();
var response=sh.alert("Add 20 DKP to all raiders?", sh.ButtonSet.YES_NO);
if(response==sh.Button.YES) {
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var raiders = activeSheet.getRange(1, 12).getValue();
// In your situation, the range is the same. So "range" is declared here.
var range = activeSheet.getRange(4, 2, raiders);
// Create values for putting to the range.
var values = range.getValues().map(function(row) {return [row[0] + 20]});
// Put the created values to the range.
range.setValues(values);
// Update the cells. Before "alert" is shown.
SpreadsheetApp.flush();
var complete=sh.alert("20 DKP has been added to all raiders.", sh.ButtonSet.OK);
}
}
However, I now want to do the same with my subtraction script that would rely on two ranges of data. I'm still very new to coding, and am basically getting by on youtube tutorials and advice from this forum. How would I implement the same change to the below code?
function spentDKP() {
alertBoxSpentDKP()
}
function alertBoxSpentDKP() {
var sh=SpreadsheetApp.getUi();
var response=sh.alert("Subtract spent DKP of all raiders?", sh.ButtonSet.YES_NO);
if(response==sh.Button.YES) {
var app = SpreadsheetApp;
var ss = app.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var raiders = activeSheet.getRange(1, 12).getValue()+4;
for(var i=4;i<raiders;i++){
var DKP = activeSheet.getRange(i,2).getValue()
var spentDKP = activeSheet.getRange(i,4).getValue();
if(spentDKP>0){
activeSheet.getRange(i,2).setValue(DKP-spentDKP)
}
}
var complete=sh.alert("All DKP has been subtracted, please clear the loot window to reset values.", sh.ButtonSet.OK);
}
}
Many thanks in advance.
Try replacing this
var raiders = activeSheet.getRange(1, 12).getValue()+4;
for(var i=4;i<raiders;i++){
var DKP = activeSheet.getRange(i,2).getValue()
var spentDKP = activeSheet.getRange(i,4).getValue();
if(spentDKP>0){
activeSheet.getRange(i,2).setValue(DKP-spentDKP)
}
}
with this
var raiders = activeSheet.getRange(1, 12).getValue();
var range = activeSheet.getRange(4, 2, raiders, 3); // Get the range with the data to be processed
var inputValues = range.getValues(); // Get the data from that range
var outputValues = inputValues.map(Subtract); // Use a function to subtract the spent DKP from the DKP balance available
range.setValues(outputValues); // post the calculated values back to the sheet
And add a helper function for map:
// Helper function for map
function Subtract(inputValuesRow) {
if (inputValuesRow[2] > 0) {
inputValuesRow[0] -= inputValuesRow[2];
}
return inputValuesRow; // This has now been change where column 4 value has been subtracted from the column 2 value
}
Edit
To preserve the formulas in the middle column, remove the Subtract helper function. And use this as the replacement:
var raiders = activeSheet.getRange(1, 12).getValue();
var range = activeSheet.getRange(4, 2, raiders, 3); // Get the range with the data to be processed
var inputValues = range.getValues(); // Get the data from that range
var outputValues = [];
for (var r = 0; r < inputValues.length; r++) {
if ( inputValues[r][2] > 0 ) {
outputValues.push([inputValues[r][0] - inputValues[r][2]])
} else {
outputValues.push([inputValues[r][0]])
}
}
activeSheet.getRange(4, 2, raiders, 1).setValues(outputValues);

How to connect autoincrement with auto_date_stamp

I have autoincremment in my google scripts. I would like add script with fixed timestamp. And connect with auto_increment in one time.
I started auto_increment script and next I start insert_timestamp
function auto_increment() {
var AUTOINC_COLUMN = 0; //start column
var HEADER_ROW_COUNT = 340;// start row
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var worksheet = spreadsheet.getSheetByName("Sheet 1");
var rows = worksheet.getDataRange().getNumRows() - 1;
var vals = worksheet.getSheetValues(1, 1, rows+1, 2);
for (var row = HEADER_ROW_COUNT; row < vals.length; row++) {
try {
var id = vals[row][AUTOINC_COLUMN];
Logger.log(id);Logger.log((""+id).length ===0);
if ((""+id).length === 0) {
// Here the columns & rows are 1-indexed
worksheet.getRange(row+1, AUTOINC_COLUMN+1).setValue(row);
}
} catch(ex) {
// Keep calm and carry on
}
}
}
function insert_timestamp() { //function onEdit() I cannot because I need fixed date one day
var s = SpreadsheetApp.getActiveSheet();
var r = s.getActiveCell();
var tz = Session.getScriptTimeZone();
if( r.getColumn() != 0 ) {
var row = r.getRow();
var time = new Date();
time = Utilities.formatDate(time, tz, "dd.MM.yyyy");//"dd.MM.yyyy hh:mm:ss");
SpreadsheetApp.getActiveSheet().getRange('C' + row.toString()).setValue(time);
}
}
When I write on cell "E" scripts insert new ID and timestamp "dd.mm.yyyy" and fixed when I change text in cell "E" date fixed the last.
Thank you for your help

Returning a cell reference when it meets a condition

I have spreadsheet with student names, ages and test scores.
I want to loop through the 4th column (student ages) which has already been sorted from lowest to highest.
The loop notes the age of the first and youngest student in cell "D1" but I want it to stop looping when it hits on a cell where the student's age is 4 years older than the student in "D1" e.g:
11 (Cell "D1")
11
11
12
12
13
14
15 (As this student is 4 years older than cell "D1", I want it to return "D6".
I would then like to repeat the process with "D6" (or whatever the cell reference will be) now being the initial starting point and returning the cell when it hits on a cell when the student is 4 years older.
Here is what I have done already. I'm really new to this, so let me apologise in advance! Any help would be appreciated as I'm really stuck.
function myFunction() {
var app = SpreadsheetApp;
var activeSheet = app.getActiveSpreadsheet().getActiveSheet();
var firstAge = activeSheet.getRange("D1").getValue()
var lastRow = activeSheet.getLastRow();
for(var i=1;i<lastrow+1;i++){
var column4 = activeSheet.getRange(i, 4).getValue();
if (column4 === firstAge + 4) {
activeSheet.getRange().getRowIndex(column4);
function my4Loop()
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var oA=[];
var age1=vA[0][3];
for(var i=1;i<vA.length;i++)
{
if(vA[i][3]-age1>=4)
{
var a1=sh.getRange(i+1,4);
oA.push(a1.getA1Notation());
age1=vA[i][3];
a1.setBackground('#ffff00');//Mark the wiener
}
}
Logger.log(oA);
return oA;
}
This might work for you:
function getCells(){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName(YOUR_SHEET_NAME);
var targetColumn = "D";
var values = sheet.getRange(targetColumn + "1:" + targetColumn + sheet.getLastRow())
.getValues();
var cursorAt = values[0];
var result = [];
values.forEach(function(item, index){
if (item[0] - cursorAt == 4) {
cursorAt = item[0];
result.push("D" + (index + 1));
}
});
return result;
}
I hope this will help you:
function myFunction() {
var app = SpreadsheetApp;
var activeSheet = app.getActiveSpreadsheet().getActiveSheet();
var lastRow = activeSheet.getLastRow();
var firstAge =activeSheet.getRange("D1:D"+lastRow).getCell(1,1).getValue();
var allval=column4=activeSheet.getRange("D1:D"+lastRow).getvalues();
for(var i=0;i<allval.length;i++){
if (allval[i][0] == firstAge + 4) {
Logger.log('Row Index:'+(i+1));
break;}
}
}

Google Sheets Go to Today button

I have a sheet with horizontal dates (starting at 1 January, ending in 31 Dec).
I'm trying to put a button in the sheet which will make it jump to "Today".
This is what I have so far:
function goToSheet(sheetName, row, col) {
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
SpreadsheetApp.setActiveSheet(sheet);
var range = sheet.getRange(1, col)
SpreadsheetApp.setActiveRange(range);
}
function goToSheet2b() {
goToSheet("2016", 1,299);
}
2016 is the sheet name, 299 is the column number for today's date and it actually jumps to today, but I would need to manually change 299 in order for it to work every day. Is there a simple way of going about this?
I'd propose to attach the button to the following "goToTodayKeepRow" function:
function goToTodayKeepRow() {
var ass = SpreadsheetApp.getActiveSpreadsheet();
var as = ass.getActiveSheet();
var today = new Date();
today.setHours(0,0,0,0);
var datesRange = as.getRange(1, 1, 1, as.getLastColumn());
for (var column = 1; column <= datesRange.getNumColumns(); column++) {
var cell = datesRange.getCell(1, column);
if (isValidDate(cell.getValue()) && cell.getValue().getTime() === today.getTime()) {
as.getRange(as.getActiveCell().getRow(), cell.getColumn()).activate();
break;
}
}
}
function isValidDate(d) {
if ( Object.prototype.toString.call(d) !== "[object Date]" )
return false;
return !isNaN(d.getTime());
}
The advantages are:
cells which don't contain a valid date are skipped, it uses the isValidDate function from this post: Run custom function if value in cell is date
the function keeps the active row, it only changes the active column, if that is not desired the line before break can be replaced with "cell.activate();"
the date compare is done with getTime() function
Try attaching this script to your button:
function activateToday() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s=ss.getActiveSheet();
var lc = s.getLastColumn();
var range = s.getRange(1, 1,1,lc).getValues();
for(var i=0;i<range[0].length;i++){
if(range[0][i].getDate()+ range[0][i].getMonth()+1 ==new Date().getDate()+new Date().getMonth()+1 ){
s.getRange(1,i+1).activate();
break;
}}}

Cannot create an all day event series into google calendar, from google forms

I have been trying for days now, reading other posts, playing with other scripts that have been close to the same purpose and nothing works. I am trying to make a script that will take information from a web based google form, along with a month/day and turn it into a re-occuring event in the Calendar.
It is finally posting to the Calendar NOW but every event comes up undefined under December 31, 2015 - with no further information, altho at least it is reoccurring.
Any help would be greatly appreciated as I try to understand this coding and how to do it. Thank you!
//this is the ID of the calendar to add the event to, this is found on the calendar settings page of the calendar in question
var calendarId = "id#group.calendar.google.com";
//below are the column ids of that represents the values used in the spreadsheet (these are non zero indexed)
var startDtId = 5;
var endDtId = 5;
var titleId = 2;
var descId = 3;
var formTimeStampId = 1;
function getLatestAndSubmitToCalendar() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var lr = rows.getLastRow();
var startDt = sheet.getRange(lr,startDtId,1,1).getValue();
//set to first hour and minute of the day.
// startDt.setHours(0);
// startDt.setMinutes(00);
var endDt = sheet.getRange(lr,endDtId,1,1).getValue();
//set endDt to last hour and minute of the day
// endDt.setHours(23);
// endDt.setMinutes(59);
// var subOn = "Submitted on :"+sheet.getRange(lr,formTimeStampId,1,1).getValue();
var desc = sheet.getRange(lr,descId,1,1).getValue();
var title = sheet.getRange(lr,titleId,1,1).getValue();
createAllDayEvent(calendarId,title,startDt,endDt,recurrence,loc,desc);
}​
function createAllDayEventSeries(calendarId,title,startDt,endDt,recurrence,loc,desc) {
var cal = CalendarApp.getCalendarById('id#group.calendar.google.com');
var start = new Date(startDt);
var end = new Date(endDt);
var loc = descId;
var desc = "Happy Birthday "+titleId+" of "+descId;
// Creates a rule that recurs every week for ten weeks.
var recurrence = CalendarApp.newRecurrence().addYearlyRule();
var event = cal.createAllDayEventSeries(title, start, recurrence, {
description : desc,
location : loc
});
};
I created a form and tested with the following code:
// Column data constants
var nameCol = 2;
var birthdayCol = 3;
var descriptionCol = 4;
var locationCol = 4;
var calendarId = '[id]#group.calendar.google.com';
/* Send Confirmation Email with Google Forms */
function Initialize() {
var triggers = ScriptApp.getProjectTriggers();
for (var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
ScriptApp.newTrigger("CreateCalendarEvent")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit()
.create();
}
function createEvent() {
var ss = SpreadsheetApp.getActiveSheet();
var rows = ss.getDataRange();
var lr = rows.getLastRow();
var start = ss.getRange(lr,birthdayCol,1,1).getValue();
start.setHours(0);
start.setMinutes(00);
var title = ss.getRange(lr,nameCol,1,1).getValue() + " Birthday";
var desc = ss.getRange(lr,descriptionCol,1,1).getValue();
var loc = ss.getRange(lr,locationCol,1,1).getValue();
var recurrence = CalendarApp.newRecurrence().addYearlyRule();
Logger.log("accessing calendar");
var externalCalendar = CalendarApp.getCalendarById(calendarId);
externalCalendar.createAllDayEventSeries(title, start, recurrence, {
description : desc,
location : loc
});
}
function getRelativeDate(daysOffset, hour) {
var date = new Date();
date.setDate(date.getDate() + daysOffset);
date.setHours(hour);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
}
function CreateCalendarEvent(e) {
try {
Logger.log("creating event");
createEvent();
} catch (e) {
Logger.log(e.toString());
}
}
This sets a trigger function when the form is submitted, make sure that you change the value of the calendar id to the one provided by your calendar.