I'm currently trying to get this piece of code to send events from a google sheet to a google calendar (Credit to Adam McFarland on this post).
My sheet is currently around 300 rows & growing so to speed things up I've set the range to start at row 248. But this then seems to throw off the part that notes the event as 'done'. It sets value of "In 2 calendar" to rows 2, 3, 4 & 5?!?
Easy solution would be just to set the range to the whole sheet again but I'm still learning. I'd like to learn what exactly here isn't working correctly, and also a bit more about how iteration works.
//mark as entered, enter ID
sheet.getRange(i+2, 32).setValue('In 2 calendar');
Complete code below:
function pushToCalendar() {
//spreadsheet variables
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(248,1,lastRow,40);
var values = range.getValues();
var updateRange = sheet.getRange('G1');
var numValues = 0;
for (var i = 0; i < values.length; i++) {
//check to see if name and type are filled out - date is left off because length is "undefined"
if ((values[i][0].length > 0) && (values[i][2].length > 0)) {
//check if it's been entered before
if (values[i][30] != 'In calendar') {
//Declare which calendar ID to use (IGNORE THIS FOR NOW)
var calendar = CalendarApp.getCalendarById('calendarID')
// if (values [i][3] != 'Tropical 2450 Pontoon'){
// var calendar = CalendarApp.getCalendarById('calendarID')
//create event https://developers.google.com/apps-script/class_calendarapp#createEvent
var newEventTitle = values[i][3]+'. '+values[i][2]+'. '+values[i][13]
+'. '+values[i][5]+'/'+values[i][6]+'/'+values[i][7]
+'. '+values[i][18]+' total, '+values[i][25]+' to pay. '+values[i][0];
// var newEvent = calendar.createEvent('hello', Date[i][1], Date[i][5]);
var newEvent = calendar.createEvent(newEventTitle,
//new Date(values[i][6]),
new Date(values[i][32]),
new Date(values[i][33]));
//{guests:'tures.com.au', sendInvites: true});
//mark as entered, enter ID
sheet.getRange(i+2, 32).setValue('In 2 calendar');
} //could edit here with an else statement
}
numValues++;
}
}
Related
Absolute noob here !
Background:
am trying to create a Google Sheet which I can update for a series of events and
create Google Calendar events based on those entries
so far, am successful in creating calendar events and also updating back the last column of the sheet with the EventID (iCalUID) - thanks to other stackoverflow posts
am also successful in not creating Duplicates by checking if the EventID (iCalUID) is already present in the last column - thanks again to other stackoverflow posts
But... have another requirement, where am failing:
need to mark an existing event as 'Cancelled' in one of the columns in the sheet and
if this is 'true' then look-up the EventID (iCalUID) from the corresponding last cell (of that row which has a 'Cancelled' entry) and
delete that particular event from the calendar
also, calendar events should NOT be created again as long as that cell remains/retains the word 'Cancelled'.
the "var check1 = row[23]; //Booked/Blocked/Cancelled" in below script was just added to bring in this logic that I wanted, but am kind of unable to proceed
Relevant screen-shot of the sheet
Code that I used so far as below:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Sync to Calendar')
.addItem('Sync Now', 'sync')
.addToUi();
}
function sync() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var calendar = CalendarApp.getCalendarById('myemailid#gmail.com');
var startRow = 2; // First row from which data should process > 2 exempts my header row
var numRows = sheet.getLastRow(); // Number of rows to process
var numColumns = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows-1, numColumns);
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var name = row[1]; //Name of Guest
var place = row[4]; //Add2
var room = row[9]; //Room Number
var inDate = new Date(row[10]); //Check-In Date
var outDate = new Date(row[11]); //Check-Out Date
var check1 = row[23]; //Booked/Blocked/Cancelled
var check2 = row[24]; //Event created and EventID (iCalUID) populated
if (check2 == "") {
var currentCell = sheet.getRange(startRow + i, numColumns);
var event = calendar.createEvent(room, inDate, outDate, {
description: 'Booked by: ' + name + ' / ' + place + '\nFrom: ' + inDate + '\nTo: ' + outDate
});
var eventId = event.getId();
currentCell.setValue(eventId);
}
}
}
I believe your goal is as follows.
You want to check the columns "X" and "Y".
When the column "X" is not Cancelled and the column "Y" is empty, you want to create a new event.
When the column "X" is Cancelled and the column "Y" is not empty, you want to delete the existing event.
When the column "X" is Cancelled, you don't want to create a new event.
In this case, how about the following modification?
Modified script:
In this script, in order to check whether the event has already been deleted, Calendar API is used. So please enable Calendar API at Advanced Google services.
function sync() {
var calendarId = 'myemailid#gmail.com'; // Please set your calendar ID.
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var calendar = CalendarApp.getCalendarById(calendarId);
var startRow = 2; // First row from which data should process > 2 exempts my header row
var numRows = sheet.getLastRow(); // Number of rows to process
var numColumns = sheet.getLastColumn();
var dataRange = sheet.getRange(startRow, 1, numRows - 1, numColumns);
var data = dataRange.getValues();
var done = "Done"; // It seems that this is not used.
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var name = row[1]; //Name of Guest
var place = row[4]; //Add2
var room = row[9]; //Room Number
var inDate = new Date(row[10]); //Check-In Date
var outDate = new Date(row[11]); //Check-Out Date
var check1 = row[23]; //Booked/Blocked/Cancelled
var check2 = row[24]; //Event created and EventID (iCalUID) populated
// I modified below script.
if (check1 != "Cancelled" && check2 == "") {
var currentCell = sheet.getRange(startRow + i, numColumns);
var event = calendar.createEvent(room, inDate, outDate, {
description: 'Booked by: ' + name + ' / ' + place + '\nFrom: ' + inDate + '\nTo: ' + outDate
});
var eventId = event.getId();
currentCell.setValue(eventId);
} else if (check1 == "Cancelled" && check2 != "") {
var status = Calendar.Events.get(calendarId, check2.split("#")[0]).status;
if (status != "cancelled") {
calendar.getEventById(check2).deleteEvent();
}
}
}
}
Reference:
Events: get
I used a previous answer (thanks kessy!) to split 7000 or so rows into 40 or so different tabs based upon values in a column. I ran the same script on another nearly identical file and I get the error "TypeError: Cannot read property 'getRange' of null (line 5, file "Code")". I tried with a greatly simplified file and get the same error. Any help getting this to work is very much appreciated.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
// This var will contain all the values from column C -> Room
var columnRoom = sheet.getRange("C:C").getValues();
// This var will contain all the rows
var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
//Set the first row as the header
var header = rows[0];
//Store the rooms already created
var completedRooms = []
//The last created room
var last = columnRoom[1][0]
for (var i = 1; i < columnRoom.length; i++) {
//Check if the room is already done, if not go in and create the sheet
if(!completedRooms.includes(columnRoom[i][0])) {
//Set the Sheet name = room (except if there is no name, then = No Room)
if (columnRoom[i][0] === "") {
var currentSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("No Room");
} else {
var currentSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(columnRoom[i][0]);
}
//append the header
currentSheet.appendRow(header);
currentSheet.appendRow(rows[i]);
completedRooms.push(columnRoom[i][0])
last = columnRoom[i][0]
} else if (last == columnRoom[i][0]) {
// If the room's sheet is created append the row to the sheet
var currentSheet = SpreadsheetApp.getActiveSpreadsheet()
currentSheet.appendRow(rows[i]);
}
}
}
I am not sure what is exactly your goal, but based on the error message you are getting it seems that you are not getting the active sheet properly. Instead, I would suggest you to specify the sheet by its name. Let's assume the desired name of the sheet you want to get is Sheet1. Then, in the first line of your function you can replace this:
var sheet = SpreadsheetApp.getActiveSheet();
with this:
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
I also optimized your code a little by removing all the unnecessary SpreadsheetApp.getActiveSpreadsheet() calls:
function myFunction() {
var ss = SpreadsheetApp.openById("SpreadsheetId");
var sheet = ss.getSheetByName('Sheet1');
// This var will contain all the values from column C -> Room
var columnRoom = sheet.getRange("C:C"+sheet.getLastRow()).getValues();
// This var will contain all the rows
var rows = sheet.getDataRange().getValues();
//Set the first row as the header
var header = rows[0];
//Store the rooms already created
var completedRooms = []
//The last created room
var last = columnRoom[1][0]
for (var i = 1; i < columnRoom.length; i++) {
//Check if the room is already done, if not go in and create the sheet
if(!completedRooms.includes(columnRoom[i][0])) {
//Set the Sheet name = room (except if there is no name, then = No Room)
if (columnRoom[i][0] === "") {
var currentSheet = ss.insertSheet("No Room");
} else {
var currentSheet = ss.insertSheet(columnRoom[i][0]);
}
//append the header
currentSheet.appendRow(header);
currentSheet.appendRow(rows[i]);
completedRooms.push(columnRoom[i][0])
last = columnRoom[i][0]
} else if (last == columnRoom[i][0]) {
// If the room's sheet is created append the row to the sheet
sheet.appendRow(rows[i]);
}
}
}
You can also run a loop within the loop and keep things server side for a faster result (at least it worked for me, I was having trouble with long spreadsheets timing out).
You have to know how many columns you want to pass over, maybe there is a better way to push the values than I have done (I only dabble in script).
function splitSheets() {
var theWorkbook = SpreadsheetApp.getActiveSpreadsheet();
var theSheet = theWorkbook.getSheetByName("Master");
//Let's delete any sheets that were previously split, so we can rerun the script again and again
var sheets = theWorkbook.getSheets();
for (i = 0; i < sheets.length; i++) {
switch(sheets[i].getSheetName()) {
case "Master":
break;
default:
theWorkbook.deleteSheet(sheets[i]);
}
}
// This var will contain all the values from column C -> Your splitting Key
var key = theSheet.getRange("C:C").getValues();
// This var will contain all the rows
var rows = theSheet.getDataRange().getValues();
//Set the first row as the header, get the range so we can keep the formatting
var headerFormat = theSheet.getRange("2:2");
//Store the rooms already created
var completedSheets = [];
//We start at i=2 because we're on row 3, row zero for the button, row one for the header
for (var i = 2; i < key.length; i++) {
//We don't want to run the loop if we've already created the blank page and the row key is also blank.
if(completedSheets.includes('Blank') && key[i][0] === ""){
//do nothing
}else{
//Check if the room is already done, if not go in and create the sheet
if(!completedSheets.includes(key[i][0]) ) {
//Set the Sheet name = unique key (except if there is no name, then = Blank)
if (key[i][0] === "") {
var currentSheet = theWorkbook.insertSheet("Blank");
} else {
var currentSheet = theWorkbook.insertSheet(key[i][0]);
}
//To avoid pasting formulas, we have to paste contents, copying allows us to keep formatting
headerFormat.copyTo(currentSheet.getRange(1,1),{contentsOnly:true});
headerFormat.copyTo(currentSheet.getRange(1,1),{formatOnly:true});
//Now here find all the rows containing the same key address and push them, this way doing it server side
var theNewRows =[];
var b=0;
for(var j = 1; j < rows.length; j++) {
if((rows[j][2] == key[i][0]) || (rows[j][2] === '' && currentSheet.getName() == "Blank")){
theNewRows[b]=[];//Initial new array
theNewRows[b].push(rows[j][0],rows[j][1],rows[j][2],rows[j][3],rows[j][4],rows[j][5],rows[j][6],rows[j][7],rows[j][8]);
b++;
}
}
var outrng = currentSheet.getRange(2,1,theNewRows.length,9);//Make the output range the same size as the output array
outrng.setValues(theNewRows);
//The new sheet name gets added to the completed sheets list and the value of var last is updated in prep of next step
if(currentSheet.getSheetName() == 'Blank') {
completedSheets.push('Blank');
last = "Blank";
}else{
completedSheets.push(key[i][0])
last = key[i][0]
}
}
}
}
//And return to the Master
SpreadsheetApp.setActiveSheet(theWorkbook.getSheetByName('Master'));
}
Example here, just click the button on the page
https://docs.google.com/spreadsheets/d/1pfeU2CFDbZbA4O0b4z80l5MyCKDNQnUdkpKlzODbAiI/edit?usp=sharing
It's not perfect, but hope it helps.
I have searched many possible answers but cannot seem to find one that works. I have a Google Sheet with about 1600 rows that I need to split into about 70 different tabs (with about 20-30 rows in each one) based on the value in the column titled “room”. I have been sorting and then cutting and pasting but for 70+ tabs this is very tedious.
I can use the Query function but I still need to create a new tab, paste the function and update the parameter for that particular tab.
This script seemed pretty close:
ss = SpreadsheetApp.getActiveSpreadsheet();
itemName = 0;
itemDescription = 1;
image = 2;
purchasedBy = 3;
cost = 4;
room = 5;
isSharing = 6;
masterSheetName = "Master";
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Update Purchases')
.addItem('Add All Rows To Sheets', 'addAllRowsToSheets')
.addItem('Add Current Row To Sheet', 'addRowToNewSheet')
.addToUi();
}
function addRowToNewSheet() {
var s = ss.getActiveSheet();
var cell = s.getActiveCell();
var rowId = cell.getRow();
var range = s.getRange(rowId, 1, 1, s.getLastColumn());
var values = range.getValues()[0];
var roomName = values[room];
appendDataToSheet(s, rowId, values, roomName);
}
function addAllRowsToSheets(){
var s = ss.getActiveSheet();
var dataValues = s.getRange(2, 1, s.getLastRow()-1, s.getLastColumn()).getValues();
for(var i = 0; i < dataValues.length; i++){
var values = dataValues[i];
var rowId = 2 + i;
var roomName = values[room];
try{
appendDataToSheet(s, rowId, values, roomName);
}catch(err){};
}
}
function appendDataToSheet(s, rowId, data, roomName){
if(s.getName() != masterSheetName){
throw new Error("Can only add rows from 'Master' sheet - make sure sheet name is 'Master'");
}
var sheetNames = [sheet.getName() for each(sheet in ss.getSheets())];
var roomSheet;
if(sheetNames.indexOf(roomName) > -1){
roomSheet = ss.getSheetByName(roomName);
var rowIdValues = roomSheet.getRange(2, 1, roomSheet.getLastRow()-1, 1).getValues();
for(var i = 0; i < rowIdValues.length; i++){
if(rowIdValues[i] == rowId){
throw new Error( data[itemName] + " from row " + rowId + " already exists in sheet " + roomName + ".");
return;
}
}
}else{
roomSheet = ss.insertSheet(roomName);
var numCols = s.getLastColumn();
roomSheet.getRange(1, 1).setValue("Row Id");
s.getRange(1, 1, 1, numCols).copyValuesToRange(roomSheet, 2, numCols+1, 1, 1);
}
var rowIdArray = [rowId];
var updatedArray = rowIdArray.concat(data);
roomSheet.appendRow(updatedArray);
}
But I always get an unexpected token error on line 51 or 52:
var sheetNames = [sheet.getName() for each(sheet in ss.getSheets())];
(And obviously the column names, etc. are not necessarily correct for my data, I tried changing them to match what I needed. Not sure if that was part of the issue.)
Here is a sample of my data: https://docs.google.com/spreadsheets/d/1kpD88_wEA5YFh5DMMkubsTnFHeNxRQL-njd9Mv-C_lc/edit?usp=sharing
This should return two separate tabs/sheets based on room .
I am obviously not a programmer and do not know Visual Basic or Java or anything. I just know how to google and copy things....amazingly I often get it to work.
Let me know what else you need if you can help.
Try the below code:
'splitSheetIntoTabs' will split your master sheet in to separate sheets of 30 rows each. It will copy only the content not the background colors etc.
'deleteTabsOtherThanMaster' will revert the change done by 'splitSheetIntoTabs'. This function will help to revert the changes done by splitSheetIntoTabs.
function splitSheetIntoTabs() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var header = rows[0];
var contents = rows.slice(1);
var totalRowsPerSheet = 30; // This value will change no of rows per sheet
//below we are chunking the toltal row we have into 30 rows each
var contentRowsPerSheet = contents.map( function(e,i){
return i%totalRowsPerSheet===0 ? contents.slice(i,i+totalRowsPerSheet) : null;
}).filter(function(e){ return e; });
contentRowsPerSheet.forEach(function(e){
//crate new sheet here
var currSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet();
//append the header
currSheet.appendRow(header);
//populate the rows
e.forEach(function(val){
currSheet.appendRow(val);
});
});
}
// use this function revert the sheets create by splitSheetIntoTabs()
function deleteTabsOtherThanMaster() {
var sheetNotToDelete ='Master';
var ss = SpreadsheetApp.getActive();
ss.getSheets().forEach(function(sheet){
if(sheet.getSheetName()!== sheetNotToDelete)
{
ss.deleteSheet(sheet);
}
});
}
I was using Kessy's nice script, but started having trouble when the data became very large, where the script timed out. I started looking for ways to reduce the amount of times the script read/wrote to the spreadsheet (rather than read/write one row at a time) and found this post https://stackoverflow.com/a/42633934
Using this principle and changing the loop in the script to have a loop within the loop helped reduce these calls. This means you can also avoid the second call to append rows (the "else"). My script is a little different to the examples, but basically ends something like:
`for (var i = 1; i < theEmails.length; i++) {
//Ignore blank Emails and sheets created
if (theEmails[i][0] !== "" && !completedSheets.includes(theEmails[i][0])) {
//Set the Sheet name = email address. Index the sheets so they appear last.
var currentSheet = theWorkbook.insertSheet(theEmails[i][0],4+i);
//append the header
//To avoid pasting formulas, we have to paste contents
headerFormat.copyTo(currentSheet.getRange(1,1),{contentsOnly:true});
//Now here find all the rows containing the same email address and append them
var theNewRows =[];
var b=0;
for(var j = 1; j < rows.length; j++)
{
if(rows[j][0] == theEmails[i][0]) {
theNewRows[b]=[];//Initial new array
theNewRows[b].push(rows[j][0],rows[j][1],rows[j][2],rows[j][3],rows[j][4],rows[j][5],rows[j][6],rows[j][7]);
b++;
}
}var outrng = currentSheet.getRange(2,1,theNewRows.length,8); //Make the output range the same size as the output array
outrng.setValues(theNewRows);
I found a table of ~1000 rows timed out, but with the new script took 6.5 secs. It might not be very neat, as I only dabble in script, but perhaps it helps.
I have done this script that successfully gets each room and creates a new sheet with the corresponding room name and adding all the rows with the same room.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
// This var will contain all the values from column C -> Room
var columnRoom = sheet.getRange("C:C").getValues();
// This var will contain all the rows
var rows = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
//Set the first row as the header
var header = rows[0];
//Store the rooms already created
var completedRooms = []
//The last created room
var last = columnRoom[1][0]
for (var i = 1; i < columnRoom.length; i++) {
//Check if the room is already done, if not go in and create the sheet
if(!completedRooms.includes(columnRoom[i][0])) {
//Set the Sheet name = room (except if there is no name, then = No Room)
if (columnRoom[i][0] === "") {
var currentSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet("No Room");
} else {
var currentSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet(columnRoom[i][0]);
}
//append the header
currentSheet.appendRow(header);
currentSheet.appendRow(rows[i]);
completedRooms.push(columnRoom[i][0])
last = columnRoom[i][0]
} else if (last == columnRoom[i][0]) {
// If the room's sheet is created append the row to the sheet
var currentSheet = SpreadsheetApp.getActiveSpreadsheet()
currentSheet.appendRow(rows[i]);
}
}
}
Please test it and don't hesitate to comment for improvements.
I have been working on a google sheet that that receives a form submission.
Once the submission comes in I need a script to move the rows of data to different tabs depending on the name shown in column C.
I have extensively searched for solutions on stack overflow and I am very close to a solution right now through the code I have found and edited.
I have a script that will move historic dates to a different tab and leave all future dates in the original tab based in the logic of the date being older than today.
All I need to do now is modify this to move the rows with the name "John" in column C to the John tab and ignore the date.
Once I can get one name to work I am confident I can make this work for multiple names and multiple tabs.
Please feel free to create a copy of the following test sheet I have been working on.
link:
https://docs.google.com/spreadsheets/d/1zJpylrD_5hzScW3lIjIQQSKiY0Aan6Wkm_h_IbVrVXM/edit#gid=0
function MovePastDates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entrySheet = ss.getSheetByName("Entry Sheet");
var franksSheet = ss.getSheetByName("Franks Sheet");
var lastColumn = entrySheet.getLastColumn();
for(var i = entrySheet.getLastRow(); i > 0; i--){
var dateCell = entrySheet.getRange(i, 1).getValue();
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 = entrySheet.getRange(i, 1, 1, entrySheet.getLastColumn()).getValues();
franksSheet.getRange(franksSheet.getLastRow() + 1, 1, 1, entrySheet.getLastColumn()).setValues(rangeToMove);
entrySheet.deleteRow(i);
}
}
}
The final result should be a google sheet that receives form entries.
Each entry will be allocated to a specific person who will only have edit permissions to there own tab only where they can approve/decline requests submitted through the form.
All other users of the sheet will have view only access.
I wanted two scripts:
1) Script to move form submission rows to a specific tab dependent on person’s name
(I was going to set up a trigger every minute for this)
2) Script to move past dates into an historic sheet
(I was going to set up a trigger every night for this)
I have been able to modify your code to achieve the desired function, it may not be the most efficient but it appears to work well.
Script One is:
function moveRowsToNamesSheets() { //Name of function
var sObj={John:'Johns Sheet',Frank:'Franks Sheet',David:'Davids Sheet'}; // Put key work and sheet name here in format eg.( keyWord1: 'sheet name to move keyWord1 to')
var ss=SpreadsheetApp.getActive(); // ??
var esh=ss.getSheetByName('Entry Sheet'); //Sheet data is being pulled form
var fsh=ss.getSheetByName('Franks Sheet'); //unsure why one of the sheets is named here
var erg=esh.getDataRange(); // Not sure of function now that I am not using dates
var evA=erg.getValues(); // ??
var d=0; //??
//var today=new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()).valueOf(); // Didnt need this line
for(var i=1;i<evA.length;i++) { //??
if(/*new Date(evA[i][0]).valueOf() < today*/ evA[i][2]=='John' ||evA[i][2]=='Frank' ||evA[i][2]=='David') { //Keywords used go here, what does the [2] mean?
ss.getSheetByName(sObj[evA[i][2]]).appendRow(evA[i]); //??
esh.deleteRow(i+1-d);
d++; //increments d by one
}
}
}
Script Two is:
function HistoricDates() {
// Initialising
var ss = SpreadsheetApp.getActiveSpreadsheet();
//--------------- Franks Sheets --------------------
var franksSheet = ss.getSheetByName("Franks Sheet");
var PastSheet = ss.getSheetByName("Historic Requests");
var lastColumn = franksSheet.getLastColumn();
// Check all values from your "Franks Sheet" sheet
for(var i = franksSheet.getLastRow(); i > 0; i--){
// Check if the value is a valid date
var dateCell = franksSheet.getRange(i, 4).getValue(); //Dates in column 4
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 = franksSheet.getRange(i, 1, 1, franksSheet.getLastColumn()).getValues();
PastSheet.getRange(PastSheet.getLastRow() + 1, 1, 1, franksSheet.getLastColumn()).setValues(rangeToMove);
franksSheet.deleteRow(i);
}
}
}
//---------------------- Johns Sheets -------------------------
var johnsSheet = ss.getSheetByName("Johns Sheet");
var pastSheet = ss.getSheetByName("Historic Requests");
var lastColumn = johnsSheet.getLastColumn();
// Check all values from your "Johns Sheet" sheet
for(var i = johnsSheet.getLastRow(); i > 0; i--){
// Check if the value is a valid date
var dateCell = johnsSheet.getRange(i, 4).getValue(); //Dates in column 4
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 = johnsSheet.getRange(i, 1, 1, johnsSheet.getLastColumn()).getValues();
pastSheet.getRange(pastSheet.getLastRow() + 1, 1, 1, johnsSheet.getLastColumn()).setValues(rangeToMove);
johnsSheet.deleteRow(i);
}
}
}
//--------------- Davids Sheets --------------------
var davidsSheet = ss.getSheetByName("Davids Sheet");
var pastSheet = ss.getSheetByName("Historic Requests");
var lastColumn = davidsSheet.getLastColumn();
// Check all values from your "Davids Sheet" sheet
for(var i = davidsSheet.getLastRow(); i > 0; i--){
// Check if the value is a valid date
var dateCell = davidsSheet.getRange(i, 4).getValue();//Dates in column 4
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 = davidsSheet.getRange(i, 1, 1, davidsSheet.getLastColumn()).getValues();
pastSheet.getRange(pastSheet.getLastRow() + 1, 1, 1, davidsSheet.getLastColumn()).setValues(rangeToMove);
davidsSheet.deleteRow(i);
}
}
}
}
// Check is a valid date
function isValidDate(value) {
var dateWrapper = new Date(value);
return !isNaN(dateWrapper.getDate());
}
The working spreadsheet is located here:
https://docs.google.com/spreadsheets/d/1VCONRkBpkva-KrFDO2bFV8ZTp1U168QWAGavcKCa_uQ/edit?usp=sharing
I think this is what you want:
function movePastDatesOrJohn() {
var sObj={John:'Johns Sheet',Frank:'Franks Sheet',David:'Davids Sheet'};
var ss=SpreadsheetApp.getActive();
var esh=ss.getSheetByName('Entry Sheet');
var fsh=ss.getSheetByName('Franks Sheet');
var erg=esh.getDataRange();
var evA=erg.getValues();
var d=0;
var today=new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()).valueOf();
for(var i=1;i<evA.length;i++) {
if(new Date(evA[i][0]).valueOf() < today || evA[i][2]=='John') {
ss.getSheetByName(sObj[evA[i][2]]).appendRow(evA[i]);
esh.deleteRow(i+1-d);
d++;
}
}
}
So Franks Sheet and Davids Sheet only get the rows that are older than today. But Johns Sheet gets all of the row that are Johns and disregards the date. I think that's what you wanted.
By the way, did you know that if you more that one form attached to your spreadsheet you can tell which response sheet the formSubmit trigger is writing too, with the event object range? Using sheet name = e.range.getSheet().getName();
I have a GAS script run from a Google Sheet with two functions. The first function downloads calendar event details in a named calendar between two dates. The name of the calendar, the start date and the end date are read in from cells A2, B2, and C2 respectively. This function is working fine:
//Function to list certain events in your GCalendar.
function listMyEvents() {
var sheet = SpreadsheetApp.getActiveSheet();
var calid = sheet.getRange("A2").getValue();
if(calid == null) {
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter a valid calendar name!');
return;
}
var startTime = sheet.getRange("B2").getValue();
if(startTime == 0) {
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter a start date!');
return;
}
if(isNaN(startTime)) {
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter a valid start date!');
return;
}
var endTime = sheet.getRange("C2").getValue();
if(endTime == 0) { //If the cell doesn't contain anything send an error prompt
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter an end date');
return;
}
if(isNaN(endTime)) { //If the cell holds text rather than a number then send an error prompt
SpreadsheetApp.getActiveSpreadsheet().toast('Please enter a valid end date!');
return;
}
var calendar = CalendarApp.getCalendarsByName(calid)[0]; //get the calendar name
var events = calendar.getEvents(startTime, endTime);
var data; //declare a variable to hold all the information.
for(var i = 0; i < events.length;i++){
var event = events[i];
data = [
event.getTitle(),
event.getDescription(),
event.getStartTime(),
event.getEndTime(),
event.getLocation(),
event.getId(),
"N"
];
sheet.appendRow(data);
}
sheet.autoResizeColumn(1);
sheet.autoResizeColumn(2);
sheet.autoResizeColumn(3);
sheet.autoResizeColumn(4);
sheet.autoResizeColumn(5);
sheet.autoResizeColumn(6);
sheet.autoResizeColumn(7);
}
The second function tries to read in the event Id from column F, in order to allow individual events to be amended within the sheet before being written back to Google Calendar. However, the script errors on the line calendarEvent.getId() with the error Cannot call method "getId" of undefined. (line 118, file "Code").
I did read that you need to use the .getEventSeriesById() method - but the events aren't in a series! Is it possible to amend individual events with a script or do I need to delete all events and recreate them with amendments? My code for the second function is here:
function amendCalEvents() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 6; // First row of data to process
var numRows = sheet.getLastRow(); // Number of rows to process
//var maxRows = Math.min(numRows,200); //Limit the number of rows to prevent enormous number of event creations
var calid = sheet.getRange("A2").getValue(); //putting the calendar name in double quotes creates double entries. Who knew?
var dataRange = sheet.getRange(startRow, 1, numRows, 7); //startRow, startCol, endRow, endCol
var data = dataRange.getValues();
var cal = CalendarApp.getCalendarsByName(calid)[0]; //get the calendar name
for (i in data) {
var row = data[i];
var title = row[0]; // column A
var desc = row[1]; // column B
var tstart = row[2]; // column C
var tstop = row[3]; // column D
var loc = row[4]; // column E
var evId = row[5]; // column F
var evDelFlag = row[6]; // column G
var event = cal.calendarEvent.getId(evId);
if (evDelFlag == "N" || evDelFlag == "n") {
event.setTitle(title);
event.setDescription(desc);
event.setTime(tstart, tstop);
event.setLocation(loc);
} else {
cal.getId(evId).deleteEvent;
}
}
}
Any help or pointers are most gratefully accepted.
There are some changes you can do in the function amendCalEvents
1.- numRows variable, you are setting the value of getLasRow but you are not subtracting the rows used for the first information (e.g. if you have just 1 calendar and this calendar has one event, when you run the first function it'll add a new row and this variable will have 3 as value.
so when you u call the function getRange, it will bring the information from 3 rows and not just the one that has the information.
2.- a workaround of using the getEventSeriesById, you can probably call again the function getEvents as you did in the first fucntion.
As you are already looping in the for with a similar amount of data you could access the element inside the array o events and set the desired values.
var event = events[i];
3.- to delete the event now you can call:
event.deleteEvent();
Hope this helps