Background
I'm trying to write a script that will check two different cells to see if the checkbox has been checked. So, it would first check one cell (AL4) to see if the value is true, and then a different cell (Q4) to see if the value is true. If the value is true, then it will run a different function.
Both of the cells I am checking are in the same sheet, "Dashboard", so it doesn't have to find different sheet names. I've been different ways to get it to check the different cells by using .getcolumn and .getrow commands but I've had some trouble with that too. I've also run into some problems where it will ignore the if statement and run the function on every edit and not just when the two cells are checked.
How can I get an if and else if statement to work in the same onEdit function?
Current Script
function onEdit(e) {
const sheetName = "Dashboard"
var range = e.range;
if (range.getSheet().getSheetName() != sheetName || range.getA1Notation() != "AL4" || !range.isChecked()) {
return;
RefreshCheckmark2();
} else if (range.getSheet().getSheetName() != sheetName || range.getA1Notation() != "Q4" || !range.isChecked()) {
return;
InverseYieldRefresh();
}
}
Also, the above code is completely functional if you remove the else if statement and the brackets after the first If statement.
Ideally I would like to be able to add more else if statements so that it can check more cells because I like to have checkboxes run commands and if my understanding is correct, you can't have more than one onEdit function in a single spreadsheet.
Thank you for any insight!
I think what you are trying to do right now is to check if it is not AL4 or Q4 rather than checking if it is AL4 or Q4. Also, in your current code, you use return; before running any function so it would really skip running the function even if it goes in your if-statement. You can try this code below:
function onEdit(e) {
const sheetName = "Dashboard"
var range = e.range;
if (range.getSheet().getSheetName() == sheetName && range.getA1Notation() == "AL4" && range.isChecked()) {
RefreshCheckmark2();
}
else if (range.getSheet().getSheetName() == sheetName && range.getA1Notation() == "Q4" && range.isChecked()) {
InverseYieldRefresh();
}
}
I only changed the conditions to make it check if it is AL4 or Q4 then removed the return; to make the functions inside the if-statements run once conditions are satisfied.
Let me know if this solves your problem.
Related
I have script for Google Sheets that I collected on interwebs and got some help here. No I have 2 onEdit in conflict. I overcome that by creating script Trigger for onEdit2. It works but I don't think it is the best solution. Could you help get those two separated onEdit with if functions into one, please?
//Dependent Dropdown list
function onEdit(e){ // Function that runs when we edit a value in the table.
masterSelector(master1,master2,master3,master4);
var activeCell = e.range; // It returns the coordinate of the cell that we just edited.
var val = activeCell.getValue(); // Returns the value entered in the column we just edited.
var r = activeCell.getRow(); // returns the row number of the cell we edit.
var c = activeCell.getColumn(); // returns the column number of the cell we edit.
var wsName = activeCell.getSheet().getName();
if (wsName === masterWsName && c === firstLevelColumn && r > masterNumberOfHeaderRows) { // the if delimits the section sensitive to modification and action of the onEdit.
applyFirstLevelValidation(val,r);
} else if (wsName === masterWsName && c === secondLevelColumn && r > masterNumberOfHeaderRows){
applySecondLevelValidation(val,r);
}
} // end of onEdit
// addRow by checkboxes
function onEdit2(e) {
masterSelector(master1,master2,master3,master4);
//IF the cell that was edited was in column 4 = D and therefore a checkbox AND if the cell edited was checked (not unchecked):
if (e.range.columnStart === 4 && e.range.getValue() === true) {
var sheet = SpreadsheetApp.getActiveSheet(),
row = sheet.getActiveCell()
.getRow(),
//(active row, from column, numRows, numColumns)
rangeToCopy = sheet.getRange(row, 1, 1, 30);
sheet.insertRowAfter(row);
rangeToCopy.copyTo(sheet.getRange(row + 1, 1));
//Reset checked boxes in column 4
sheet.getRange(row,4,2,1).setValue(false);
}
}
Whole script is here, if needed.
A script cannot contain two functions with the same name. Rename your first onEdit function to onEdit1 (actually it will be better to assign a descriptive name) and the second function as onEdit2, then put them both in one function named onEdit and pass the parameter e to both of them:
function onEdit(e){
onEdit1(e);
onEdit2(e);
}
Related:
Two OnEdit functions not working together
Best Practices for Multiple OnEdit Functions
How to run multiple onEdit functions in the same google script (google sheets)?
Bracketing multiple onEdit functions
I have this function looping through all sheets, and if the sheet is not hidden, add the sheet name to the array out.
function sheetnames() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var out = new Array()
for (var i=0 ; i<sheets.length ; i++)
if (sheets[i].isSheetHidden()!= true){
out.push( [ sheets[i].getName() ]
)}
Logger.log(out);
}
I would also like to test for specific sheet names, which I am able to do with
if (sheets[i].getSheetName()!= 'Sheet1'){
However when I put them together with || an OR operator, both tests are ignored.
if (sheets[i].isSheetHidden()!= true || sheets[i].getSheetName()!= 'Sheet1'){
I'm not sure if it is the way I am handling || or something else I'm not seeing.
In this example, sheet1 is visible, so would pass the first part of the test.
(sheets[i].isSheetHidden()!= true || sheets[i].getSheetName()!= 'Sheet1')
will return true if the current sheet is not hidden or not named 'Sheet1'. Or in other words, it will only return true if the current sheet is named 'Sheet1' and is hidden. That's probably not what you want, is it? Perhaps what you're looking for is the && AND logical operator?
Also, I'd suggest you look into formatting code, why you should use !== instead of !=, and see this question for information on using var a = []; compared to var b = new Array();
I have this code that works for restricting data in all cells to 5 characters. I like that it shortens the data back to 5 characters if you put more that 5 in.
function onEdit(e) {
var limit = 5;
if(e.value.length > limit) {
e.range.setValue(e.value.substring(0, limit));
}
}
If I click the Run button it does show an error.
TypeError: Cannot read property "value" from undefined. (line 3, file "Code")
But it seems to work fine.
I would like to have the script work on a certain range of cells only. Say C3:C100. So I had to reference the sheet and cells, so changed the script to this.
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("C3:C100");
var limit = 5;
if(e.value.length > limit) {
e.range.setValue(e.value.substring(0, limit));
}
}
This script does not work on any of the cells, let alone the selected ones.
Can anyone help me please? What have I missed?
A onEdit script is triggered by any edit in a spreadsheet. It 'captures' the edit in what is called an event object. The event object can be passed as an argument to the function. In that case you'll see onEdit(e) or onEdit(event) as the function name. That object has some parameters attached to it: e.range (the edited range), e.value (the value of the edit), e.source (the spreadsheet where the edit is done), etc..
Now when you run the function from the script editor (by clicking the play button) no actual edit is taking place in the spreadsheet. Therefore no event object will be created and all parameters of that object will be undefined.
If you want to 'limit' the scope of the script to the range C3:C100, you can change the script as follows:
function onEdit(e) {
var limit = 5;
if (e.value.length > limit && e.range.rowStart > 2 && e.range.rowStart < 101 && e.range.columnStart == 3) {
e.range.setValue(e.value.substring(0, limit));
}
}
Note that currently the script will work on every tab/sheet inside your spreadsheet/workbook. If you want to further limit the script to work on only one sheet (e.g. 'Sheet1'), you can try something like
function onEdit(e) {
var limit = 5;
if (e.source.getActiveSheet().getName() == 'Sheet1' && e.value.length > limit && e.range.rowStart > 2 && e.range.rowStart < 101 && e.range.columnStart == 3) {
e.range.setValue(e.value.substring(0, limit));
}
}
I have a Google Sheet I'm working on.
I have a script that fills in the column B with a timestamp when I update column A on the first tab. However I need it to do the same on the second tab, but I can't get it to work there. What do I need to change?
The current script I'm using is:
function onEdit(e) {
var sheetToWatch= 'Wrong Grading',
columnToWatch = 1,
columnToStamp = 2; //change all of these to your needs
if (e.range.columnStart !== columnToWatch
|| e.source.getActiveSheet().getName() !== sheetToWatch
|| !e.value)
return;
e.source.getActiveSheet()
.getRange(e.range.rowStart, columnToStamp)
.setValue(new Date());
}
For future readers, the code snippet in Paul's question is derived from code on the Google Docs help forum, which includes a detailed line-by-line explanation.
The function uses the variable sheetToWatch to identify one sheet (aka "tab") that the onEdit() function cares about. That is validated by this comparison:
|| e.source.getActiveSheet().getName() !== sheetToWatch
...and if the source of the current trigger event is not matched, the function exits without doing anything.
What do I need to change? If you want this function to work on all sheets in the Spreadsheet, then you can just eliminate this check altogether:
function onEdit(e) {
var columnToWatch = 1,
columnToStamp = 2; //change all of these to your needs
if (e.range.columnStart !== columnToWatch
|| !e.value)
return;
e.source.getActiveSheet()
.getRange(e.range.rowStart, columnToStamp)
.setValue(new Date());
}
If you want to have the onEdit() operate on a set of sheets, then you can change that above comparison to check if the current sheet's name is found in an array of sheet names. That will change the comparison to this:
|| sheetsToWatch.indexOf( e.source.getActiveSheet().getName() ) === -1
You can learn more about the indexOf() method here. What it's doing though, is getting the name of the event trigger source sheet, finding it in the sheetsToWatch array, and returning the found index. If the sheet does not appear in the array, indexOf() returns -1.
The resulting function is:
function onEdit(e) {
var sheetsToWatch= ['Wrong Grading',
'Something Else'],
columnToWatch = 1,
columnToStamp = 2; //change all of these to your needs
if (e.range.columnStart !== columnToWatch
|| sheetsToWatch.indexOf( e.source.getActiveSheet().getName() ) === -1
|| !e.value)
return;
e.source.getActiveSheet()
.getRange(e.range.rowStart, columnToStamp)
.setValue(new Date());
}
I'm really trying to avoid nesting in this code snippet...
deal_trade_in_model_1 = document.getElementById('deal_trade_in_model_1').value;
deal_trade_in_amount_1 = document.getElementById('deal_trade_in_amount_1').value;
if (typeof deal_trade_in_model_1 !== 'undefined' && deal_trade_in_model_1 !== null) {
console.log(deal_trade_in_amount_1);
console.log(deal_trade_in_model_1);
if (deal_trade_in_model_1 !== null || deal_trade_in_model_1 !== "") {
if (deal_trade_in_amount_1 == null || deal_trade_in_amount_1 == "") {
console.log('entered into function');
document.getElementById("deal_trade_in_model_1").value = "";
document.getElementById("deal_trade_in_amount_1").value = "";
}
}
}
Basically, what this function does is take the value of two fields... things to know about them and what I want to do to them:
1) They're NOT required
2) If one of them is filled out, the other must be
3) If ONLY one of them is filled out, the user clicks submit, and this part of the function is called upon, I want to delete the value of both of them.
I've tried doing a compound of
&& (and)
and
|| (or)
buttttt it odiously it didn't work.
Primary question: What's the best way to get rid of the nesting (I planned on doing this twice and just swapping the code) that will be the most efficient? This, I want, to be done preferably in the smallest amount of IF statements possible.
Please note: If you change the code a lot, I might not know what you're talking about.. please be prepared to teach me or help me learn!
It sounds like you only want to do something if either of the fields are empty, but not both. Assuming both of the elements are text fields, .value will always return a string. Converting a string to boolean results in false if the string is empty, otherwise true.
So
Boolean(deal_trade_in_model_1) === Boolean(deal_trade_in_amount_1)
will be true if either both fields have a value (both will convert to true) or both fields are empty (both convert to false).
Thus your code can be reduced to
var model_1 = document.getElementById('deal_trade_in_model_1');
var amount_1 = document.getElementById('deal_trade_in_amount_1');
if (Boolean(model_1.value) !== Boolean(amount_1.value)) {
model_1.value = "";
amount_1.value = "";
}