I am having issues making this work. I want to insert todays date in colum 4 upon making checkbox true in colum 1. There are multiple rows. I am not seeing the error of my ways. Any suggestions would be appreciated.
Thanks,
function onEdit(e) {
var ss = e.source.getActiveSheet();
var date = new Date();
if (e.range.columnStart != 1 || e.value != "TRUE") return;
ss.getRange(e.range.rowStart,4).setValue(date);
}
Instead of:
E.value != "TRUE"
Simply use:
!e.value
And then instead of:
ss.getRange(e.range.rowStart,4).setValue(date)
You can simply use:
e.range.offset(0,3).setValue(date)
That allows you to eliminate the need for the ss variable as well.
Related
I want to add some quick filters using the ui of google sheets. Currently I want to allow the user to click "show last month" to only see the data of the last month. The dates are written in the first column.
Now I prefer to use the filter of google sheets before just printing the values into the sheet, to allow the user to further modify that filter.
Thus I am trying to build filterCriteria using SpreadsheetApp.newFilterCriteria().whenDateEqualToAny(dates) and I am parsing an array of valid dates. In the documentation it says I have to put a "Date[]" - doesn't that mean an array of dates?
Below the error message and my code:
Error message (linked to the line "var filterCriteria..."):
"Exception: The boolean condition can not have multiple values for equality checks for non-data source objects"
My code:
function showLastMonth() {
var ss = SpreadsheetApp.getActive()
var sheet = ss.getSheetByName('evaluation')
var now = new Date()
var thisYear = now.getFullYear()
var thisMonth = now.getMonth()
if(thisMonth == 0){var startMonth = 11; var startYear = thisYear - 1}
else{var startMonth = thisMonth - 1; var startYear = thisYear}
var startDate = new Date(startYear, startMonth, 1)
var endDate = new Date(thisYear, thisMonth, 0)
var dates = getDateArray(startDate, endDate)
var filter = sheet.getFilter()
if(filter == null ){
var range = sheet.getDataRange()
var filter = range.createFilter()
}
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenDateEqualToAny(dates)
filter.setColumnFilterCriteria(1, filterCriteria)
}
getDateArray = function(startDate, endDate){
var startYear = startDate.getFullYear()
var startMonth = startDate.getMonth()
var dateArray = []; dateArray.push(startDate)
var date = startDate; var day = date.getDay()-1
while(date<endDate){
day++
date = new Date(startYear, startMonth, day)
if(date<=endDate){dateArray.push(date)}
}
return dateArray;
}
I believe your goal as follows.
You want to hide the rows of the values except for dates using the basic filter.
You want to achieve this using Google Apps Script.
Issue and workaround:
In the current stage, it seems that array of whenDateEqualToAny(array) is required to be the length of 1. I think that this is the reason of your issue. So for example, when var filterCriteria = SpreadsheetApp.newFilterCriteria().whenDateEqualToAny([dates[0]]) is used, no error occurs. This situation is the same with the setBasicFilter request of Sheets API. Unfortunately, it seems that this is the current specification. But, the official document says The acceptable values. which uses the plural form. Ref So I also think that this is not correct for the actual situation as mentioned by TheMaster's comment.
In order to achieve your goal, in this case, I would like to propose the following 2 patterns.
Pattern 1:
In this pattern, using setHiddenValues(), the values except for the values of dates in your script are set as the hidden values.
Modified script:
When your script is modified, please modify as follows.
From:
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenDateEqualToAny(dates)
To:
var obj = dates.reduce((o, e) => Object.assign(o, {[`${e.getFullYear()}\/${e.getMonth() + 1}\/${e.getDate()}`]: true}), {});
var range = sheet.getRange("A1:A");
var dispValues = range.getDisplayValues();
var hiddenValues = range.getValues().reduce((ar, [a], i) => {
if (a instanceof Date && !obj[`${a.getFullYear()}\/${a.getMonth() + 1}\/${a.getDate()}`]) {
ar.push(dispValues[i][0]);
}
return ar;
}, []);
var filterCriteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(hiddenValues).build();
Pattern 2:
In this pattern, using whenNumberBetween(), the values of dates in your script are shown. In this case, it is required to convert the date object to the serial number.
Modified script:
When your script is modified, please modify as follows.
From:
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenDateEqualToAny(dates)
To:
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenNumberBetween(
(dates[0].getTime() / 1000 / 86400) + 25569,
(dates.pop().getTime() / 1000 / 86400) + 25569
).build();
The conversion from the date object to the serial number was referred from this thread.
References:
setHiddenValues(values)
whenNumberBetween(start, end)
Using the code below, the google sheet enters the Date in column 6 when a cell in column 1 is edited. It also includes the timestamp.
How can this code be altered so that just the date (day-month-year) is entered? This would allow searches by date on the sheet.
function onEdit(e) {
var sheetName = 'Cases Allocation'; //name of the sheet the script should work on
var colToWatch = 1
var colToStamp = 6 //timestamp in col A
if (e.range.columnStart !== 1 || e.source.getActiveSheet()
.getName() !== sheetName || e.value == '') return;
var writeVal = e.value !== "" ? new Date(),: '';
e.source.getActiveSheet()
.getRange(e.range.rowStart, colToStamp)
.setValue(writeVal);
}
You can try using Utilities.formatDate. This method formats date according to specification described in Java SE SimpleDateFormat class. You can visit the date and time patterns here. An example of usage is:
// This formats the date as Greenwich Mean Time in the format
// year-month-dateThour-minute-second.
var formattedDate = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd'T'HH:mm:ss'Z'");
Logger.log(formattedDate);
Do take note that using Utilities.formatDate has the following effects as noted in this post:
Utilities.formatDate does not change the cell format; it converts
its content to text. If you are going to use the date value in
computations, you don't want it to be converted to text.
Utilities.formatDate requires one to specify a timezone. If you put
something like "GMT+1" and your country observes Daylight Saving
Time, you can expect hard-to-track bugs to come up a few months
later. With setNumberFormat, the date value remains consistent with
all other date values in the spreadsheet, governed by its timezone
setting.
To avoid these, you can also use setNumberFormat(numberFormat) to set the date or number format. The accepted format patterns are described in the Sheets API documentation. And an example usage is:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cell = sheet.getRange("B2");
// Always show 3 decimal points
cell.setNumberFormat("0.000");
Thanks all - tried format etc, but then just decided to add a column and split the date and time, with just the date going into a new column.
function onEdit(e) {
var sheetName = 'Cases Allocation'; //name of the sheet the script should work on
var colToWatch = 1
var colToStamp = 6 //timestamp in col A
if (e.range.columnStart !== 1 || e.source.getActiveSheet()
.getName() !== sheetName || e.value == '') return;
//var writeVal = e.value !== "" ? new Date(),: '';
e.source.getActiveSheet()
.getRange(e.range.rowStart, colToStamp)
.setValue(new Date(new Date().setHours(0,0,0,0))).setNumberFormat('MM/dd/yyyy');
}
The below code will save the date without time. You can change the format as required. The field remains a date which can be used as required.
setValue(new Date(new Date().setHours(0,0,0,0))).setNumberFormat('MM/dd/yyyy');
I wrote this script that is used as a trigger onEdit in a sheet. The idea is to pick a value from a worksheet, copy it into another worksheet based on some logic, and then delete the source row that contained the original value.
When run, often times, the copy will take place, but on delete, the copied value will disappear. One way I noticed fixes the problem is if I delete the trigger, save, and create it again...
How can I avoid this behavior?
function onEdit(e) {
var range = e.range;
var entry = range.getSheet();
var sss = entry.getParent();
if (sss.getName() != "Weight Tracker")
return;
if (entry.getName() != "Entry")
return;
Logger.log("CopyData is running...."+range.getCell(1,2).getValue());
var weight = range.getCell(1,2).getValue();
Logger.log("weight = "+weight);
var details = sss.getSheetByName('Details');
var trange = details.getRange(3, 1, 200);
var data = trange.getValues();
var today = new Date().setHours(0,0,0,0);
for(var n=0;n<data.length;n++) {
var date = new Date(data[n]).setHours(0,0,0,0);
Logger.log("date = "+date+" =? "+today);
if(date == today) {
break
};
}
Logger.log("n = "+n+" today: "+today);
// n is 0 based, sheet is 1 based + 2 headers = 3, 5 is Jim's weight
details.getRange(n+3,5).setValue(weight);
// get rid of the row so next addition arrives to the top row
Logger.log("deleting row...");
// for some reason deleting the road removes the value entered...
range.getSheet().deleteRow(1);
}
I have created a google spreadsheet. On the column A in row 1 I have used "vastzetten" (that's in dutch). The first column and row I have blocked. When I go with the cursor I can change the date and the rest of the sheet dissapeared after the block. (Look the images). Is there a way when I start the sheet it selects the date of the day then moves the rest of the sheet after the titleblock? I hope that somebody knows what I mean.
You could use an installable trigger to hide columns and/or to activate the range corresponding to the current date.
For instructions on how to set an installable trigger see https://developers.google.com/apps-script/guides/triggers/installable
The following code assumes that the column headers are values of date type. If the current date is found, then the columns at the left will be hidden and the the cell below the corresponding header will be activated.
function myFunction(){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheets()[0];
var tz = ss.getSpreadsheetTimeZone();
var today = Utilities.formatDate(new Date(), tz, 'YYYY-MM-dd')
var data = sheet.getDataRange().getValues();
var headers = data[0];
for(var i = 0;i<= headers.length;i++){
if(headers[i] instanceof Date){
if(today == Utilities.formatDate(headers[i], tz, 'YYYY-MM-dd')){
sheet.hideColumns(2,i-1);
sheet.getRange(2, i+1).activate();
break;
}
}
}
}
I'm currently working on a script for a spreadsheet.
Desired Behavior: When cells F-I are edited, the date of the most recent edit should be returned in cell L of the corresponding row.
I've found two samples of code, the first returns the date in cell L when ANY field in the row is edited. This behavior is acceptable, but not ideal as it applies to any col
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
var r = s.getActiveCell();
if( r.getColumn() != 2 ) {
var row = r.getRow();
var time = new Date();
time = Utilities.formatDate(time, "GMT-05:00", "yyyy-MM-dd");
SpreadsheetApp.getActiveSheet().getRange('L'+row.toString()).setValue(time);
};
};
The second should return the date one cell to the right of the edited column. This behavior is not desired as it may overwrite other important data.
function onEdit(e) {
var s = SpreadsheetApp.getActiveSheet();
var cols = [1, 7, 13, 19, 25, 31]
if (s.getName() !== "Sheet1" || cols.indexOf(e.range.columnStart) == -1) return;
s.getRange(e.range.rowStart, e.range.columnStart + 1)
.setValue(new Date());
};
Any help or advice on editing these to behave more closely to the desired results would be much appreciated. Thanks!
Something like this should work:
function onEdit(e) {
var ss = e.source.getActiveSheet();
var watchedCols = [6, 7, 8, 9]
if (watchedCols.indexOf(e.range.columnStart) === -1) return;
ss.getRange(e.range.rowStart, 12)
.setValue(e.value ? Utilities.formatDate(new Date(), "GMT-05:00", "yyyy-MM-dd") : null)
}
Note that the script will work on every sheet of your google spreadsheet. If you want to limit it to only one sheet (and also exclude edits in the first row (headers ?)), you could try something like this:
function onEdit(e) {
var ss = e.source.getActiveSheet();
var watchedCols = [6, 7, 8, 9];
var watchedSheet = 'Sheet1'; //change name if needed
if (watchedCols.indexOf(e.range.columnStart) === -1 || ss.getName() !== watchedSheet || e.range.rowStart < 2) return;
ss.getRange(e.range.rowStart, 12)
.setValue(e.value ? Utilities.formatDate(new Date(), "GMT-05:00", "yyyy-MM-dd") : null)
}
Hope that helps ?