IF function in Google Sheets (scripts) with dates (today) - google-apps-script

what could be wrong in these code?
...
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Daty'), true);
var today = spreadsheet.getRange('B1').getValue()
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('ZNC'), true);
var changeday = spreadsheet.getRange('E2').getValue()
var nrrej = spreadsheet.getRange('A2')
if(nrrej!=="" && changeday<today)
{Browser.msgBox("Info");
}else{
...
Script does not take these conditions into consideration together. Separately it is OK.

Answer
You are comparing a range with a string.
How to fix it
The variables today and changeday are values. They are defined as getRange('X').getValue(). However, nrrej is a range and you are comparing it with a string (""). The best approach to check if a cell is blank is using the function isBlank. It returns true if the range is totally blank.
Final code
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Daty'), true);
var today = spreadsheet.getRange('B1').getValue()
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('ZNC'), true);
var changeday = spreadsheet.getRange('E2').getValue()
var nrrej = spreadsheet.getRange('A2').isBlank()
if (nrrej == false && changeday < today) {
Browser.msgBox("Info");
} else { }
Some advice
Use the debugger to check the status of the variables before getting an error
Use automatic indentation with ctrl + shft + I
References
Range
Range: isBlank
Range: getValue
Use the debugger and breakpoints

Related

How do I compare Times in Google Apps Script

I am trying to create a filter on a list based on a given time interval (2 cells in my spreadsheet which will input a timestamp C4 and C5). I have scoured the internet for a while and found out that the Javascript code used in Google Apps Script is different from the usual Javascript, so I haven't found a usable code snippet for my case.
The code is something like this:
var beginningTimeValue = new Date('2020-01-01 ' + ss.getRange("C4").getValue());
var endingTimeValue = new Date('2020-01-01 ' + ss.getRange("C5").getValue());
if(!beginningTimeValue == ""){
Logger.log(beginningDateValue);
unique = unique.filter(function(row)
{
const bTime = Date.parse(row[4]);
Logger.log(bTime);
Logger.log(beginningTimeValue);
return bTime.getTime() >= beginningTimeValue.getTime();
}
);
}
The value in row[4] is of DateTime value ("12/01/2021 00:03:35" for example). How do I filter this row out if I want the time to be between 08:00:00 and 13:00:00?
Three points:
To filter by two conditions instead of one, simply combine the two conditions with an && operator.
So:
return bTime.getTime() >= beginningTimeValue.getTime(); && bTime.getTime() <= endingTimeValue.getTime()
instead of
return bTime.getTime() >= beginningTimeValue.getTime();
Do not use both Date.parse() and getTime() simultaneously, since they both do the same.
const bTime = Date.parse(row[4]);
already returns you a timestamp in ms, if you try to apply
bTime.getTime()
on it - this will result in an error.
Be careful with
Logger.log(beginningDateValue);
given that your variable is called beginningTimeValue and not beginningDateValue.
Sample
Provided that beginningTimeValue, endingTimeValue and unique look like the harcoded values below, the following code snippet will work correctly for you:
function myFunction() {
var beginningTimeValue = new Date('2020-01-01 08:00:00');
var endingTimeValue = new Date('2020-01-01 13:00:00');
var unique = [["value","value","value","value","12/01/2021 00:03:35","value"],["value","value","value","value","01/01/2020 00:03:35","value"], ["value","value","value","value","01/01/2020 08:03:35","value"], ["value","value","value","value","01/01/2020 13:03:35","value"]]
if(!beginningTimeValue == ""){
Logger.log(beginningTimeValue);
unique = unique.filter(function(row)
{
const bTime = Date.parse(row[4]);
Logger.log(bTime);
Logger.log(beginningTimeValue);
return bTime >= beginningTimeValue.getTime() && bTime <= endingTimeValue.getTime();
}
);
console.log("unique: " + unique)
}
}
UPDATE
If you want to compare the times only (not the dates), you need to hardcode the date of row[4] to the same value like in beginningTimeValue and endingTimeValue. For this you can use the methods setDate(), setMonth and setYear.
Also, if your code should only work base don either vlaues are provided by a user in the cells C4 and C5 - you should adapt your code accordingly.
Be careful with your conditional statements: Even if ss.getRange("C4").getValue() is an empty string or an invalid input - beginningTimeValue will still not be an empty string, but rather the beginning of Unix time.
Sample:
function myFunction() {
var beginningTimeValue = new Date('2020-01-01 ' + ss.getRange("C4").getValue());
console.log("beginningTimeValue: " + beginningTimeValue)
var endingTimeValue = new Date('2020-01-01 ' + ss.getRange("C5").getValue());
console.log("endingTimeValue: " + endingTimeValue)
var unique = [["value","value","value","value","12/01/2021 00:03:35","value"],["value","value","value","value","01/01/2020 00:03:35","value"], ["value","value","value","value","01/01/2020 08:03:35","value"], ["value","value","value","value","01/01/2020 13:03:35","value"]]
if(!ss.getRange("C4").getValue() == ""){
Logger.log("beginningTimeValue: " + beginningTimeValue);
unique = unique.filter(function(row)
{
const bTime = new Date(row[4]);
bTime.setYear(2020);
// Be careful - months start in Javascript with 0!
bTime.setMonth(0);
bTime.setDate(1);
Logger.log(bTime);
if(ss.getRange("C5").getValue() != ""){
return bTime >= beginningTimeValue.getTime() && bTime <= endingTimeValue.getTime();
}
else{
return bTime >= beginningTimeValue.getTime();
}
}
);
console.log("unique: " + unique)
}
}
Keep im mind that Stackoverflow is not there to provide you a complete solution, but rather to help you troubleshooting and provide you references and samples that will guide you in the right direction. This will allow to incorporate the necessary modification into your code. You still need to have some basic understanding about coding to apply the sample to your script correctly.

take the substring out of string in salesforce

I am creating the HTML template in Salesforce and below is the value I am fetching from one field that is building address. However, I just need the building number from the entire address. Below is the scenario.
“Václavské náměstí 785/28, P1 - Alfa Building”, this is the text and I want to extract the only the number i.e 785/28. But the thing is the numbers before and after the ‘/’ varies it can be more than 3 or 2 digits. Trim Left and Right work but can't seem to specify the values dynamically.
Thanks
Please find the code for your above concern. It is in javascript only.
<script>
function myFunction() {
var str = "sdfdfv123456/789xvxcv"; // pass your string over here
var revstr = reverseString(str);
var firstDigit = str.match(/\d/)
var lastDigit = revstr.match(/\d/)
var findex = str.indexOf(firstDigit);
var lindex = str.length - revstr.indexOf(lastDigit);
function reverseString(str) {
if (str === "")
return "";
else
return reverseString(str.substr(1)) + str.charAt(0);
}
var sub_string = str.substring (findex, lindex);
alert(sub_string) ;
}
</script>
If any confusion please let me know.

Detect formula errors in Google Sheets using Script

My ultimate goal is here, but because I've gotten no replies, I'm starting to learn things from scratch (probably for the best anyway). Basically, I want a script that will identify errors and fix them
Well, the first part of that is being able to ID the errors. Is there a way using Google Script to identify if a cell has an error in it, and return a particular message as a result? Or do I just have to do an if/else that says "if the cell value is '#N/A', do this", plus "if the cell value is '#ERROR', do this", continuing for various errors?. Basically I want ISERROR(), but in the script
Use a helper function to abstract away the nastiness:
function isError_(cell) {
// Cell is a value, e.g. came from `range.getValue()` or is an element of an array from `range.getValues()`
const errorValues = ["#N/A", "#REF", .... ];
for (var i = 0; i < errorValues.length; ++i)
if (cell == errorValues[i])
return true;
return false;
}
function foo() {
const vals = SpreadsheetApp.getActive().getSheets()[0].getDataRange().getValues();
for (var row = 0; row < vals.length; ++row) {
for (var col = 0; col < vals[0].length; ++col) {
if (isError_(vals[row][col])) {
Logger.log("Array element (" + row + ", " + col + ") is an error value.");
}
}
}
}
Using Array#indexOf in the helper function:
function isError_(cell) {
// Cell is a value, e.g. came from `range.getValue()` or is an element of an array from `range.getValues()`
// Note: indexOf uses strict equality when comparing cell to elements of errorValues, so make sure everything's a primitive...
const errorValues = ["#N/A", "#REF", .... ];
return (errorValues.indexOf(cell) !== -1);
}
If/when Google Apps Script is upgraded with Array#includes, that would be a better option than Array#indexOf:
function isError_(cell) {
// cell is a value, e.g. came from `range.getValue()` or is an element of an array from `range.getValues()`
const errorValues = ["#N/A", "#REF", .... ];
return errorValues.includes(cell);
}
Now that the v8 runtime is available, there are a number of other changes one could make to the above code snippets (arrow functions, etc) but note that changing things in this manner is not required.
Update: 25 March 2020
#tehhowch remarked "If/when Google Apps Script is upgraded with Array#includes, that would be a better option than Array#indexOf".
Array.includes does now run in Apps Script and, as anticipated provides a far more simple approach when compared to indexOf.
This example varies from the previous answers by using a specific range to show that looping through each cell is not required. In fact, this answer will apply to any range length.
The two key aspects of the answer are:
map: to create an array for each column
includes: used in an IF statement to test for a true or false value.
function foo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourcename = "source_sheet";
var source = ss.getSheetByName(sourcename);
var sourcerange = source.getRange("A2:E500");
var sourcevalues = sourcerange.getValues();
// define the error values
var errorValues = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A","#ERROR!"];
// loop though the columns
for (var c = 0;c<5;c++){
// create an array for the column
var columnoutput = sourcevalues.map(function(e){return e[c];});
// loop through errors
for (var errorNum=0; errorNum<errorValues.length;errorNum++){
// get the error
var errorvalue = errorValues[errorNum]
// Logger.log("DEBUG: column#:"+c+", error#:"+e+", error value = "+errorvalue+", does col include error = "+columnoutput.includes(errorvalue));
// if the error exists in this column then resposnse = true, if the error doesn't exist then response = false
if (columnoutput.includes(errorvalue) != true){
Logger.log("DEBUG: Column#:"+c+", error#:"+errorNum+"-"+errorvalue+" - No ERROR");
} else {
Logger.log("DEBUG: column#:"+c+", error#:"+errorNum+"-"+errorvalue+"- ERROR EXISTS");
}
}
}
return;
}
Shorter yet, use a nested forEach() on the [vals] array, then check to see if the cell value matches a value of the [errorValues] array with indexOf. This was faster than a for loop...
function foo() {
const errorValues = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A","#ERROR!"];
const vals = SpreadsheetApp.getActive().getSheets()[0].getDataRange().getValues();
vals.forEach((val,row) => { val.forEach((item, col) => {
(errorValues.indexOf(item) !== -1) ? Logger.log("Array element (" + row + ", " + col + ") is an error value.") : false ;
});
});
}
I had a similar question and resolved using getDisplayValue() instead of getValue()
Try something like:
function checkCells(inputRange) {
var inputRangeCells = SpreadsheetApp.getActiveSheet().getRange(inputRange);
var cellValue;
for(var i=0; i < inputRangeCells.length; i++) {
cellValue = inputRangeCells[i].getDisplayValue();
if (cellValue=error1.....) { ... }
}
}
Display value should give you what's displayed to the user rather than #ERROR!

Approval Process: 'e.parameter.approval' inside an "if" cycle

I'm trying to build an Approval flow with Google Apps Script. I would also like to add an "if" cycle that creates a Calendar event if e.parameter.approval is true.
So, everything works but the system doesn't recognize the "if" cycle. I've tried this:
function doGet(e){
var answer = (e.parameter.approval == 'true') ? 'Approved!' : 'Not this time';
MailApp.sendEmail(e.parameter.reply, "Request",
"The answer is: "+ answer);
// here I tried both with (e.parameter.approval === 'true') and (check === answer) and also with "=" "==" and "==="...
var check = 'Approved!';
if(e.parameter.approval === 'true'){
var calendar = CalendarApp.getCalendarById('xxxxxxx')
//create event
var newEventTitle = 'Event Test';
var newEvent = calendar.createAllDayEventSeries(newEventTitle,
Date,
CalendarApp.newRecurrence().addDailyRule().times(10),
{description:'test'});
//get ID
var newEventId = newEvent.getId();
}
var app = UiApp.createApplication();
app.add(app.createHTML('<p><br><h2>An email was sent to '+ e.parameter.reply + ' saying: '+ answer + '</h2>'))
return app
}
Do you have any idea why the system skips the "if" cycle and goes directly to "var app"?
e.parameter.approval might not be returning anything. I could be "undefined". It could be "null". You need to know for sure what e.parameter.approval is doing. There is also the possibility that the if condition is actually working, but then there is an error that kills the code and stops it. You'll need to debug every line. Try using the "debug" tool.
Apps Script Debugging Tool
You are using:
if(e.parameter.approval === 'true'){
The word 'true' is in quotes, which means it's a string value, not a true/false value.
Try:
if(e.parameter.approval === true){

Setting Script Property using it in "if" in Google

I have a script that is supposed to mail a chart URL when a metric falls out of X range and Only if someone has entered a new metric. It's mailing everytime I run the script so I know the setProperty is not working and the "if" statement isn't working because it's only supposed to mail if X is TRUE.
The sheet... https://docs.google.com/spreadsheet/ccc?key=0Ai_2YLvaQba0dHN1dWFpY0ZSbGpudWF4cTJYNlFwNHc&usp=sharing
My code...
function myAverages() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var value = ss.getSheetByName("EmailServices").getRange("P2").getValue().toString();
var outside = ss.getSheetByName("EmailServices").getRange("S2").getValue().toString;
var mailed = ss.getSheetByName("EmailServices").getRange("T2").getValue().toString();
var stemiAverage = ss.getSheetByName("EmailServices").getRange("R2").getValue().toString();
var stemiChart = ss.getSheetByName("EmailServices").getRange("U2").getValue().toString();
var last = ScriptProperties.getProperty('last');
//if "value" is not equal to ScriptProperty "last" AND "outside" is TRUE, then mail
if(value =! last, outside = "TRUE")
{
MailApp.sendEmail("dave#mydomain.com", "Metric Warning",
"Yearly STEMI Average has fallen below 65%, it is now: " + stemiAverage + "%" +
"\n\nTo see the current trending chart " + stemiChart + "\n\n The sheet that calculated this is here " + ss.getUrl());
ScriptProperties.setProperty('last','value');
}
}
Thanks for any help you can lend. I'm teaching myself this stuff and feel very much like a newby. I've tried a hundred or more combinations to the script before posting here.
As a complement to Phil's answer and following your comment, there is another error in your script :
ScriptProperties.setProperty("last","value");
should be
ScriptProperties.setProperty({'last':value},true);
The true parameter is optional, see documentation on ScriptProperties, it gives you the possibility to delete all other keys.
So you're complete function with corrections would be :
function myAverages(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var value = ss.getSheetByName("EmailServices").getRange("P2").getValue().toString();
Logger.log('value = '+value)
var outside = ss.getSheetByName("EmailServices").getRange("S2").getValue().toString();
Logger.log('outside='+outside)
var mailed = ss.getSheetByName("EmailServices").getRange("T2").getValue().toString();
Logger.log('mailed = '+mailed)
var stemiAverage = ss.getSheetByName("EmailServices").getRange("R2").getValue().toString();
var stemiChart = ss.getSheetByName("EmailServices").getRange("U2").getValue().toString();
var last = ScriptProperties.getProperty('last');
Logger.log('last='+last)
if(value != last && outside == "true"){
MailApp.sendEmail("me#mydomain.com", "Metric Warning",
"Yearly STEMI Average has fallen below 65%, it is now: " + stemiAverage + "%" +
"\n\nTo see the current trending chart " + stemiChart + "\n\n The sheet that calculated this is here " + ss.getUrl());
ScriptProperties.setProperty({'last':value});
Logger.log('mail sent')
}
}
You need to use the AND operator: &&.
And also, checking for equality requires 2 equals signs: ==.
So be sure you try this:
if (value!=last && outside=="TRUE") {