I want to compare two cells and depending on whether they are equal or not send out different e-mails. After having read several articles on this topic I unfortunately do not see why the the following comparison with === always gives out as a result that the cells are different, even if I compare the same cells:
function SendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var ui = SpreadsheetApp.getUi(); // var file = SpreadsheetApp.getActiveSheet();
if (sheet.getRange(2,10) === sheet.getRange(2,10)) {
MailApp.sendEmail("ab#gmail.com", "test", "not equal!");
} else {
MailApp.sendEmail("ab#gmail.com", "test", "equal!");
}
}
It also does not work if I use !==.
Any hint is highly aprreciated - thanks!
You need to compare the values in the cells rather than the Ranges themselves.
If you are dealing with single cells, this is straightforward:
if(sheet.getRange(2,10).getValue() === sheet.getRange(2,10).getValue())
However if you want to compare ranges with multiple cells it is more complex, as you'll need to compare arrays of values.
I noticed you were comparing the same cells? I changed it to compare cells J2 & K2 and to log the differences. I hope this helps.
function SendEmail() {
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var ui = SpreadsheetApp.getUi(); // var file = SpreadsheetApp.getActiveSheet();
Logger.log(sheet.getRange(2,10).getValue());// logs value of J2
Logger.log(sheet.getRange(2,11).getValue());// Logs the value of K2
if(sheet.getRange(2,10).getValue() === sheet.getRange(2,11).getValue()) {
// MailApp.sendEmail("ab#gmail.com", "test", "equal!");
Logger.log('equal');
} else {
// MailApp.sendEmail("ab#gmail.com", "test", "not equal!");
Logger.log('not equal');
}
}
The return type for the getRange() method is Range, which inherits from Object. Objects are reference types and will never be considered equal unless the variables being compared point to the same object instance.
As mentioned, you need to call the getValue() method on the range that will return the contents of the cell and compare the values.
Related
I just have started coding in google script and stuck on this step of checking the cell is blank or not .length is working fine with string but not with non-string characters.
My google script Snapshot
My google sheet snapshot
Also some people suggested to use LEN function but I can't find any method "LEN" in google script. Please suggest I'm unable to get clear answer on internet.
Edit:
my exact code is here for better reference
const sheetName = "Sheet1";
const sheet =SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
//var activeCellAddress = activeCell.getA1Notation();
function create_challan() {
check_range1=sheet.getRange(1,6).getDisplayValues()
check_range2=sheet.getRange(9,6).getDisplayValues()
if (check_range1.length == 0 && check_range2.length == 0) {
console.log(`Cell A6 is empty.`);
} else {
console.log(`Cell A6 is not empty.`);
}
}
When getValues is used, when the cell value is a number value, a date object, and a boolean value, the number, date object, and boolean (Object[][]) are returned, respectively. By this, when length is used, undefined is returned. I thought that this situation might be the reason for your current issue of but not with non-string characters..
In order to use length, in this case, how about using getDisplayValues instead of getValues? By this, all values are retrieved as the string value (String[][]). By this, length can be used for checking whether the cell value is empty. When this is reflected in a sample script, how about the following sample script?
Sample script:
function myFunction() {
const sheetName = "Sheet1"; // Please set your sheet name.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const range = sheet.getRange("A2:A" + sheet.getLastRow());
const values = range.getDisplayValues();
for (let i = 0; i < values.length; i++) {
if (values[i][0].length == 0) { // or values[i][0] == ""
console.log(`Cell A${i + 2} is empty.`);
} else {
console.log(`Cell A${i + 2} is not empty.`);
}
}
}
When this script is used for your provided sample image when the cells are "A2" and "A6", Cell ## is not empty. is shown in the log. And, other cells show Cell ## is empty..
Note:
Above sample script uses multiple cells. When you want to check only one cell, getValue and getDisplayValue can be also used for one cell of the same situation. But, in this case, isBlank of Class Rnage might be useful. When this is reflected in a sample script, it becomes as follows.
function myFunction() {
const sheetName = "Sheet1"; // Please set your sheet name.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
if (sheet.getRange("A2").isBlank()) {
console.log(`Cell A2 is empty.`);
} else {
console.log(`Cell A2 is not empty.`);
}
}
References:
getValues()
getDisplayValues()
isBlank()
I'm kind of new to working with Google Sheets, and I've stumbled across an issue while creating buttons for a ticket system. I've been having trouble getting the copied data to just fill the other sheet from the second row and down without gaps or overwriting existing data.
The script basically checks if a checkbox of a certain row is ticked, copies the data in that row, moves that data to another sheet, and then resets that row to it's original state. Meaning it doesn't completely delete the row or format, but only copies the contents.
Here's the code I've been working with so far:
function MigrateInProgress() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Copy of New Tickets');
var s2 = ss.getSheetByName('In Progress');
var r = s.getRange('G:G');
var v = r.getValues();
var dataset = [];
for(var i=v.length-1;i>=0;i--)
if(v[0,i]=='true') {
var data = s.getRange(i+1,1,1,6).getValues();
s2.getRange(i+1,s2.getLastColumn()-6,data.length,6).setValues(data);
var datasetrange = s.getRange(i+1,1,1,6);
datasetrange.clear({contentsOnly: true});
datasetrange.clear({formatOnly: false});
s.getRange(i+1,7).setValue(false);
}
}
Here's some screenshots to help contextualize what I mean:
Screenshot 1
Screenshot 2
Screenshot 3
Any help would be greatly appreciated. Thank you!
I believe your goal is as follows.
You want to copy the rows of columns "A" to "F" of the source sheet to the destination sheet when the checkbox of column "G" is checked.
At that time, you want to clear the columns "A" to "F" and uncheck the column "G". And, you want to copy the values to the destination sheet without including the empty rows.
In this case, how about the following modification?
Modified script:
function MigrateInProgress() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Copy of New Tickets');
var s2 = ss.getSheetByName('In Progress');
var v = s.getRange('A2:G' + s.getLastRow()).getValues();
var { values, clear, uncheck } = v.reduce((o, r, i) => {
if (r[6] === true) {
var row = i + 2;
o.values.push(r.splice(0, 6));
o.clear.push(`A${row}:F${row}`);
o.uncheck.push(`G${row}`);
}
return o;
}, { values: [], clear: [], uncheck: [] });
console.log(values)
if (values.length > 0) {
s2.getRange(s2.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
s.getRangeList(clear).clearContent();
s.getRangeList(uncheck).uncheck();
}
}
In this modification, at first, all values are retrieved from the source sheet. And create the values for copying to the destination sheet, and also create the range list for clearing the cells and unchecking the checkboxes.
By the way, the values retrieved by getValues is 2 dimensional array, and in this case the checkbox returns the boolea type. So when you want to use v[0,i]=='true', you can use v[i][0] === true.
About some unclear points, I guessed as follows.
I couldn't understand whether where you want to put the values when the values are copied to the destination sheet. So in this modification, the values are appended to the destination sheet. When you don't want to append the values, please modify s2.getRange(s2.getLastRow() + 1, 1, values.length, values[0].length).setValues(values); to s2.getRange(2, 1, values.length, values[0].length).setValues(values);. By this, the values are always put from the row 2.
References:
reduce()
clearContent() of Class RangeList
uncheck() of Class RangeList
I want to get a simple function working where I want the script to compare an excel cell that can only have two options of strings "INSERIR" or "IGNORAR" and make the interface switch to one sheet or another.
I am new to Google Sheets and Javascript.
Here is my code:
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var source_cell = spreadsheet.getRange("C3");
if (source_cell == 'INSERIR') {
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('INSERIR ORÇAMENTO 1'), true);
} else {
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('MENU PRINCIPAL'), true);
}
Issue:
The current approach compares a range object (the result of getRange) to a string.
Solution:
You need to get the value of cell C3:
function myFunction() {
var spreadsheet = SpreadsheetApp.getActive();
var source_cell = spreadsheet.getSheetByName('Sheet1').getRange("C3").getValue();
if (source_cell == 'INSERIR') {
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('INSERIR ORÇAMENTO 1'), true);
}
else if (source_cell == 'IGNORAR') {
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('MENU PRINCIPAL'), true);
}
}
Note:
If you apply getRange directly to the spreadsheet object, you will get the value C3 of the currently active sheet. If this is what you want, then fine. However, I recommend you get the sheet by its name so your code does not depend on the active sheet.
Change Sheet1 to the sheet name where C3 has the value you would like to get.
I use an else if statement because your current code will switch to MENU PRINCIPAL if the value is different from INSERIR but as far as I understand you want to switch to MENU PRINCIPAL only when C3 is IGNORAR.
I am using this script function to check if my cell functions in sheet has any errors or not.
Here is the code but it does not seems to be working. It keeps on saying no error when i have an error in a cell
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourcename = "Sheet1";
var source = ss.getSheetByName(sourcename);
var cell = source.getRange("A1:AG30");
function isError2(cell) {
const errorValues = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A","#ERROR!"];
if (errorValues.includes(cell) != true) {
Logger.log("no error");
} else{
Logger.log("some error");
}
}
function isError2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourcename = "Sheet1";
var source = ss.getSheetByName(sourcename);
var cell = source.getRange("A1:AG30");
const errorValues = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A","#ERROR!"];
if (errorValues.includes(cell) != true) {
Logger.log("no error");
} else{
Logger.log("some error");
}
}
Updated the approach but still having no luck with the desired output
var mysheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var sheet1 = SpreadsheetApp.setActiveSheet(mysheet);
function findErrors(sheet) {
const errorValues = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A","#ERROR!"];
var singleSheetArray = [];
var name = sheet1.getName();
// how many cells in the sheet currently
var maxRows = sheet1.getMaxRows();
var maxCols = sheet1.getMaxColumns();
var totalCells = maxRows * maxCols;
// how many cells have data in them
var r = sheet1.getLastRow();
var c = sheet1.getLastColumn();
var data_counter = r * c;
if (data_counter !== 0) {
var dataRange = sheet1.getRange(1,1,r,c);
var dataValues = dataRange.getValues();
dataValues.forEach(function(row) {
row.forEach(function(cell) {
if ((errorValues.indexOf(cell) === -1) ) {
SpreadsheetApp.getUi().alert("no errors in "+cell);
data_counter --;
}
});
});
}
}
Problem
Unable to check whether the cell has an error
Explanation
The issue you are facing is a simple type mismatch. getRange() method returns an instance of Range, while you try to compare it to a member of a errorValues array, which consists of strings. Therefore, errorValues.includes(cell) will always be false, hence first block of the conditional statement executing.
Solution
Use getValues() on the range, it will return you a 2-dimensional array of values. If you are only interested in one row (which you probably are), extract it and loop over the cells with some (or every) method, doing the same comparison.
Notes
On using global variables in custom functions and in GAS in general. You can use them, GAS environment is a JavaScript runtime with a convenience layer that simplifies working with Google APIs, nearly everything that's valid in JS is valid here. That being said, do treat global variables as if they don't exist - unless you know exactly what you are doing.
References
getRange method reference
getValues method reference
Custom functions guide
every method reference on MDN (see some there)
Try to move the 4 variables inside your function. Apps script does not support global variables. So the function does not recognize the var cell.
EDIT: Detect formula errors in Google Sheets using Script
I am trying to delete a row's data based on the active cell. I have looked through Google's documentation and I cannot figure out how to do this. I have also searched the forums and found a couple of similar scenarios, but I cannot get it to work. I tried to do this by lopping through an array of data and deleting the row based on the value in the array, but this does not work either. I am sure that I am overcomplicating things here. Here is the code that I have so far...
function clearProject() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getSheetByName('Projects');
var sourceArray = source.getRange(1,1,10).getValues();
var sourceCell = source.getActiveCell();
var sourceData = sourceCell.getValues();
//var sourceRow = sourceCell.getRange(sourceCell, );
var target = ss.getSheetByName('Timeline').getRange(1, 1, 10).getValues();
for (var i = 0; i < sourceArray.length; i++){
if(i == sourceData){
sourceCell.clearContent();
}
}
Thank you for any help that you can afford!
First of all you cannot compare like this if(i == sourceData) due to getValues returns
...the rectangular grid of values for this range. Returns a
two-dimensional array of values, indexed by row, then by column. The
values may be of type Number, Boolean, Date, or String, depending on
the value of the cell. Empty cells will be represented by an empty
string in the array. Remember that while a range index starts at 1, 1,
the JavaScript array will be indexed from [0][0].
And I didn't catch your goal, could you plesae add some more explanation?
It could be as simple as that :
function delRowsInActiveRange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getActiveRange();
var height = source.getValues().length;
var rowPosition = source.getRowIndex();
ss.getActiveSheet().deleteRows(rowPosition, height);
}
This function deletes all the rows that include selected cells.