I found this script (below) and it works when simply typing in the number zero into Column G but it does not work when the result of column G comes from subtracting the values of column E and F. When the values become 0, it is left in the sheet "default". Any help would be appreciated. I have searched and find nothing about how this works when applied to the result of a formula. Thanks!
function onEdit() {
// moves a row from a sheet to another when a magic value is entered in a column
// adjust the following variables to fit your needs
// see https://productforums.google.com/d/topic/docs/ehoCZjFPBao/discussion
var sheetNameToWatch = "default";
var columnNumberToWatch = 7; // column A = 1, B = 2, etc.
var valueToWatch = 0;
var sheetNameToMoveTheRowTo = "toMoveTo";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange);
sheet.deleteRow(range.getRow());
}
}
the script works as intended. I created a test spreadsheet with the script and did the following tests:
Enter random numbers in Column A — as expected nothing happened
Entered 0 in Column A — as expected nothing happened.
Entered random number in Column G (7) — nothing happened
Entered 0 in Column G — that row was moved to the other sheet
Entered 5 in columns E and F and =E3-F3 which equals to 0 (in that order) — row was moved to the other sheet
Entered 5 in column E and 4 in column F and in column G I wrote the formula =E3-F3 which resulted in 1. After that, I changed F4 to value 5 and formula recalculates to 0 — as expected, the row is not moved.
Please make sure that the formula actually returns a value of 0. It may be that your cell is formatted to write 0.1 as 0 and the formula returns a number 0 < n < 1 which would not be moved as it must be exactly 0 in order for this to work. If you wish to move values greater than 0 but less than 1, introduce a Math.floor() against the read value.
In test scenario 6 we have to note that the script does not account for changes made to any column other than G (column number 7) because you are only watching var range = sheet.getActiveCell(); so if you change anything other than the column where you are supposed to have 0 it will not do anything because of the following if statement part range.getColumn() == columnNumberToWatch
Related
I have the following onEdit function
function onEdit(e) {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange('D2:D');
range.createTextFinder('[^0-9]').useRegularExpression(true).replaceAllWith(');
It removes all characters (text and special) from the cell, leaving only the numbers.
However, I would like it to be executed only if Column B says “after x hours”.
For example:
Cell B2 is equal to “após x horas”, so I want the above function to be executed in cell D2, when I enter something in it — that is, if I paste some data into D2, all characters will be removed, just sticking the numbers, because B2 is “após x horas”.
Cell B3 is equal to “7 dias ”, so the function should not be executed — that is, when I write something in cell D3, the characters CANNOT be removed.
How to do this?
You need to declare the two conditions and execute the replace action only when the conditions are met:
B2 = 'apox...'
B3 != '7 dias'
So your code should be like this:
let first_condition = "após x horas"
let second_condition = "7 dias"
function onEdit(e) {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange('D2:D');
if (sheet.getRange('B2:B2').getValues()[0][0].trim() == first_condition
&& sheet.getRange('B3:B3').getValues()[0][0].trim() !== second_condition) {
range.createTextFinder('[^0-9]').useRegularExpression(true).replaceAllWith('');
console.log("Cleaning out non valid characters")
}
else {
console.log("Skipping the cleaning process")
}
}
You probably need to adjust the conditions and I suggest to remove the logs.
I'm close, but my logic just isn't quite working. I am able to run the code below within Google Sheets Scripts to create a calendar event for each row in the sheet. I am trying to get it to only create an event when a new row is entered and to only read the spreadsheet until it comes to the first column/row being empty/null. enter image description here
Here is the associated code:
function createCalendarEvent() {
var sheet = SpreadsheetApp.getActiveSheet();
var calendar = CalendarApp.getCalendarById('dentaldigitaldesign.bkp#gmail.com');
var startRow = 100; // First row of data to process - 100 exempts my header row and adds to the case number count.
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 complete = "TRUE";
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var caseID = row[0]; //Case ID Number
var patient = row[4]; //Patient Name
var doctor = row[5]; //Doctor
var contact = row[14]; //Doctor contact info
var tooth = row[15]; //Tooth number
var shade = row[10]; //Tooth Shade
var notes = row[8]; //Notes
var callNotes = row[7]; //Call notes if there are any
var timeStamp = new Date (row[2]); //Retrieve the timestamp field
// year as 4 digits (YYYY)
var year = timeStamp.getFullYear();
// month as 2 digits (MM)
var month = ("0" + (timeStamp.getMonth() + 1)).slice(-2);
// date as 2 digits (DD)
var day = ("0" + timeStamp.getDate()).slice(-2);
var dueDate = new Date(month + day, + year); //Due date
var rDate = new Date(row[2]-1); //Remind date
var caseComplete = row[3]; //Case marked as complete
if (caseComplete !== complete && caseID !== null) {
var currentCell = sheet.getRange(startRow + i, numColumns);
calendar.createEvent(patient, rDate, rDate, {
description: doctor + '\r' + patient + '\r' + contact + '\r' + dueDate + '\r' + tooth + '\r' + shade + '\r' + notes + '\r' + callNotes
});
currentCell.setValue(complete);
}
}
}
When these events are created, they are all created for 8:59am. Ideally, I could do a check on the calendare if an event is set for that time, a new event is added immediately after. (perhaps in 15min or 30min slots). For now it works well for me to get the reminders on cases that are due, but eventually an invite to the doctor for them to know the due date might work well, too.
I can also use help in formatting the description field as it is not pushing the return value and everything is on one line.
And finally, the script continues to run on numerous fields beyond the scope of the desired rows, ultimately ending up with the script failing because too many event attempts are created in too short a time. (all the attempts with fields that are empty do not result in any events being created, but it is a resouce issue....and who knows maybe Google eventually blocks me?)
I appreciate any help that can be offered.
Here is the link to the Google Sheet. No data on it is sensitive as it is only test data: https://docs.google.com/spreadsheets/d/1M9qYzSl1PnRv-GehHEYvpiag15UI_GjnanA0wgA4xmg/edit?usp=sharing
There are several issues with your code, causing this expression to always return true, so that the script tries to create an event for each row:
if (caseComplete !== complete && caseID !== null) {
Empty string !== null:
You want to check whether the cell in column A is empty (that is, whether its value is an empty string), and to do that you are comparing its value to null. null is not the same as an empty string, so the following expression will always be true (a cell value never returns null):
caseID !== null
You should be comparing this to an empty string. For example, like this:
caseID !== ""
So the if statement should be:
if (caseComplete !== complete && caseID !== "") {
Wrong complete column:
Once an event has been created, you want to set the corresponding cell in D to TRUE. You're not doing that, since you specify the last column in the sheet (numColumns) when setting the currentCell:
var currentCell = sheet.getRange(startRow + i, numColumns);
Because of this, the value in D never changes to TRUE, so caseComplete !== complete is always true.
You should specify the correct column index for D instead, which is 4. It should be like this:
var currentCell = sheet.getRange(startRow + i, 4);
Edit: Also, the retrieved value for cell with checked checkboxes is the boolean true, and you're trying to compare it with the string TRUE. Because of this, this condition is not working correctly. Please change:
var complete = "TRUE";
To
var complete = true;
Wrong number of rows in source range:
You want to get the value from row 100 till the last one in the sheet. In this case, the total number of rows in the range should be the last row (numRows) minus the first row in the range (startRow) plus one (numRows - startRow + 1). The dataRange should be defined like this instead:
var dataRange = sheet.getRange(startRow, 1, numRows - startRow + 1, numColumns);
Reference:
Class Range
null
I am trying to add another line of code to this code to get the 'green' cells to switch back to 'yellow' after a given amount of time. would I add another function or add another else statement? Is it possible to nest the utilities.sleep function in one more time and only trigger it if a greater than condition is met?
In addition if I wanted this to go across rather than columns and pinpoint specific cells that represent tables. Think of a hostess with her seating chart could this be done in the offset clause for rows. and could this code also be run on another sheet and just show the checkboxes to the hostess while the color change and time stamp are run on another sheet?
Right now I have created a time stamp that only satisfies 2 conditions. Un clicked go to green and clicked go to red after a certain amount of time. If I need to create another function who would I run both functions or do I just add more var to the current function to include satisfying my 3rd condition of green to yellow showing a stag-net table ready to be seating while red is showing they have been at the table a long time but its still occupied
function onEdit(e) {
var s = SpreadsheetApp.getActiveSheet(); // the active sheet (no need to check if the sheet == sheet1 as the active sheet will always be the one that's being edited)
var r = e.range; // the range of the edited cell
var c = r.getColumn(); // the column of the range
var timeDelay = 5; // number in seconds
var checkbox = r.getValue(); // the value of the checkbox after being
edited
var date = new Date(); // the date for the timestamp
if (c == 3 && checkbox === true) { // if the checkbox has been checked,
change the color to red
var nextCell = r.offset(0,1);
Utilities.sleep(timeDelay * 100); // Utilities.sleep takes a number in
milliseconds
nextCell.setValue(date).setBackground("red");
} else if (c == 3 && checkbox === false){ // unchecked switch to green
var nextCell = r.offset(0,1);
nextCell.setValue(date).setBackground("green");
Utilities.sleep(timeDelay * 1);
}
}
any time I try to add another else statement I can not and if I add another condition to the green else if to get it to turn to yellow after x amount of minutes it skips go to green and goes right to yellow instead of vacillating between the two
Perhaps you could use something like this:
function onEdit(e) {
var r = e.range;
var c = r.columnStart;
var date = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyyMMdd HH:mm:ss");
if(e.range.columnStart==3 && e.value) {
switch (Number(e.value)) {
case 1:
e.range.offset(0,1).setValue(date).setBackground("red");
break;
case 2:
e.range.offset(0,1).setValue(date).setBackground("green");
break;
default:
e.range.offset(0,1).setValue(date).setBackground("yellow");
break;
}
}
}
how can I add leading zero to my column when my column's value is less than 10?
here is my code:
db.all("SELECT * FROM tablename WHERE x= ? ORDER BY MEMBER_CODE DESC LIMIT 1",[x], function(err,rows) {
if(rows.length == 0)
{
var mcode = 0;
}
else
{
var mcode = rows[0].MEMBER_CODE;
if (mcode < 10) {
mcode = "0"+mcode;
console.log(mcode);
}
} db.run("INSERT INTO f11 MEMBER_CODE VALUES $MEMBER_CODE",{ $MEMBER_CODE : +mcode+1});
From the code, MEMBER CODE increments every input. I tried that code but it fails. the output of console.log(mcode) which appends zero less than 10 is the one i want but it doesnt append zero anymore when the data will be processed on the database
console.log(mcode) outputs 01,02,03,04,05,06,...,10++
BUT
+mcode+1 outputs 1,2,3,4,5,6,...,10++
Please bear with my question and my explanation. Thanks
This question already has answers here:
How to convert VBA script to Google Apps Script automatically?
(3 answers)
Closed 1 year ago.
I have the VBA code below. I don't know how it works, but I want to convert it to Google Sheets.
I'm hoping someone can either:
Explain to me what the VBA is doing so that I can, perhaps, reason it out enough to work on programming it as Google Apps script,
or
Show me how the same VBA function would be achieved through Google Sheets.
Function getData(targetName As String, targetSheet As String, targetDate)
Application.Volatile True
Dim res As Double
Dim col As Integer
Dim cell As Range
Dim names As Range
Dim lastrow As Long
With ThisWorkbook.Worksheets(targetSheet)
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
col = Application.Match(targetDate, .Range("4:4"), 0)
If col = 0 Then
getData = CVErr(xlErrNA)
Exit Function
End If
Set names = .Range(.Cells(4, "A"), .Cells(lastrow, "A"))
For Each cell In names
If cell = targetName Then
res = res + cell.Offset(, col - 1)
End If
Next cell
End With
getData = res
End Function
Here's a link to an example excel file where the function is being used:
https://www.dropbox.com/s/h5vcjv9tlh1vvg7/Resources%20and%20Projects%20Full%20Example.xlsm
Though I am not familiar with Google Apps scripting, I can help you with the first part.
The point of the function appears to be adding up all values where the name found in column A matches targetName passed in as a parameter and the date found in row 4 matches targetDate, which is also a parameter. (Row is determined by name and column is determined by date.) The total value is then returned as a double.
Here's line by line comments.
Function getData(targetName As String, targetSheet As String, targetDate)
Application.Volatile True 'I don't see a reason for this line
Dim res As Double
Dim col As Integer
Dim cell As Range
Dim names As Range
Dim lastrow As Long
With ThisWorkbook.Worksheets(targetSheet) 'All ranges start with ThisWorkbook.'targetSheet'
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row 'Get the last row with data in column A to 'lastrow'
col = Application.Match(targetDate, .Range("4:4"), 0) 'Find 'targetDate' in row 4 and set it to 'col'
If col = 0 Then 'Couldn't find 'targetDate'
getData = CVErr(xlErrNA) 'Function returns the appropriate error
Exit Function 'Exit the function after setting the return value
End If
Set names = .Range(.Cells(4, "A"), .Cells(lastrow, "A")) 'Setting the range from A4 to A'lastrow' to 'names'
For Each cell In names 'Looping through every 'cell' in the 'names' range
If cell = targetName Then 'If the 'cell' value matches the 'targetName' passed in as a parameter
res = res + cell.Offset(, col - 1) 'Add the value from the column with the 'targetDate' to 'res'
End If
Next cell
End With
getData = res 'Return the total
End Function