I want to add the current data and time in a specific column with any edit in whole sheet. I tried to write a script and got a little bit success but could not get desired result.
When I run the below script then it insert the time stamp in the very next column but I want to insert the timestamp in a specific column e.g in Column D.
Secondly it only works when I change values in a cell, but I want to add time stamp also when I change even color of a cell too.
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Sheet1" ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( r.getColumn() ) { //checks the column
var nextCell = r.offset (0,1) ;
// if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date() );
}
}
}
Kindly help me to get the desired result.
if you want to insert the timestamp in a specific column e.g in Column D:
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Sheet1" ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( r.getColumn() ) { //checks the column
var nextCell = s.getRange('D' + r.getRow()); // change D to any column needed
// if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date() );
}
}
}
Notes:
onEdit(e) runs when a user changes a value in a spreadsheet.
tests show onEdit runs when cells borders are changed
onEdit does NOT run when color is changed, font is changed.
Related
I'm trying to move new hires from a list of open positions in sheet "Open Roles" to "Hired" based on selecting the option "Hired" from a drop down list in column H/8 ("Stage"). I created asample doc here.
I'm new at this and put the below into script editor (that I got from another thread) but when I hit run it returns "TypeError: Cannot read property 'source' of undefined" and "Open Roles" appears red as if it doesn't recognize it.
Can anyone help identify what I'm doing wrong or missing please? Thanks so much in advance!
function onEdit(e) {
const src = e.source.getActiveSheet();
const r = e.range;
if (src.getName() != "Open Roles" || r.columnStart != 8 || r.rowStart == 1) return;
const dest = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Hired");
src.getRange(r.rowStart,1,1,8).moveTo(dest.getRange(dest.getLastRow()+1,1,1,8));
src.deleteRow(r.rowStart);
}
However, remember the debugger is your friend. I suggest you set a variable to src.getName(), set a breakpoint to the following line and inspect the value.
var nme = src.getName();
If it is not the name of the tab then you know that is the issue.
Strange though, I made a copy of your sheet and it seems to move rows to the Hired tab. It moves any one that is changed though, not just of it is marked Hired.
I added an check to see if the value is "Hired"
function onEdit(e) {
const src = e.source.getActiveSheet();
const r = e.range;
if (src.getName() !== "Open Roles" || r.columnStart !== 8 || r.rowStart == 1) return;
const dest = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Hired");
if (src.getRange(r.rowStart,8).getValue() == "Hired") {
src.getRange(r.rowStart,1,1,8).moveTo(dest.getRange(dest.getLastRow()+1,1,1,8));
src.deleteRow(r.rowStart);
}
}
I reworked the code a bit, not sure if it will solve the undefined error but it is cleaner, I prefer one return whenever possible.
function onEdit(e) {
const src = e.source.getActiveSheet();
const r = e.range;
var sheetName = src.getName();
if (src.getName() == "Open Roles" && r.columnStart == 8 && r.rowStart !== 1) {
const dest = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Hired");
if (src.getRange(r.rowStart,8).getValue() == "Hired") {
src.getRange(r.rowStart,1,1,8).moveTo(dest.getRange(dest.getLastRow()+1,1,1,8));
src.deleteRow(r.rowStart);
}
}
}
This script does not rely on the object "e" passed to onEdit()
function onEdit(e) {
//const src = e.source.getActiveSheet();
const src = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Open Roles");
Logger.log(src);
var activeRange = src.getActiveRange();
const currRow = activeRange.getRowIndex();
const currCol = activeRange.getColumn();
Logger.log(currRow);
Logger.log(currCol);
var sheetName = src.getName();
if (src.getName() == "Open Roles" && currCol == 8 && currRow !== 1) {
const dest = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Hired");
if (src.getRange(currRow,8).getValue() == "Hired") {
src.getRange(currRow,1,1,8).moveTo(dest.getRange(dest.getLastRow()+1,1,1,8));
src.deleteRow(currRow);
}
}
}
Findings:
The reason why you're getting the TypeError: Cannot read property 'source' of undefined is because you can't run the onEdit(e) function directly from the Apps Script editor as it needs to pass data for the parameter e which will only happen when you perform an edit action on your sheet. You can view this explanation for more details.
Recommendation:
You can try & run this sample script instead without the parameter e:
function onEdit() {
var sheet = SpreadsheetApp.getActive();
var selectedCell = sheet.getActiveSheet().getCurrentCell().getA1Notation(); //Get selected cell location on Column H (in A1 notation)
var value = sheet.getActiveSheet().getRange(selectedCell).getValue(); //Get the selected value from dropdown
const dest = sheet.getSheetByName("Hired"); //The destination sheet
if(value.toString().includes("Hired")){ //Check if the selected value from the dropdown was "Hired"
var selectedRange = selectedCell.split(""); //Gets the range of the selected cell
Logger.log("\"Hired\" found on range "+ "A"+selectedRange[1]+":"+selectedCell); //Logs the result for review. Range starts in column A to H based on selected row number
sheet.getActiveSheet().getRange("A"+selectedRange[1]+":"+selectedCell).moveTo(dest.getRange(dest.getLastRow()+1,1,1,8));
SpreadsheetApp.getActiveSpreadsheet().toast("Done moving data from "+"A"+selectedRange[1]+":"+selectedCell+" to \"Hired\" sheet");
sheet.getActiveSheet().deleteRow(selectedRange[1]); //Delete the row of the selected cell from the "Open Roles" sheet
}else{
//Do nothing if the selected dropdown value is not "Hired"
}
}
RESULT:
Sample "Open Roles" sheet:
When H2 was set to "Hired," you'll see a toast message on "Open Roles" sheet:
Sample "Hired" sheet:
Here's the Execution Logs:
I have been searching for a while and trying to work together a script from various answered topics that will allow me to adjust an adjacent cells content based on the data entered. I cannot seem to get it to work properly and need some help steering the ship the right direction. Here is what I am trying to accomplish:
--If the value of cell A2:A is a six digit number AND the value of cell D2:D (same row) is "MATCH" then the value for cell B2:B should be set to "ANN"
--If the value of cell A2:A is a six digit number AND the value of cell D2:D (same row) is "NO MATCH" then the value for cell B2:B should be set to "ANN" and a drop-down data validation list of ['ANN','RNW'] populate WITH the default value of the list set to "ANN"
--If the value of cell A2:A has a length of seven or greater characters then a drop-down data validation list of ['1DY','RNW','NEW'] populate WITH the default value of the list set to "1DY"
Is it even possible to set the value of a data validation cell to a specific, default value? This is important as when the user is entering data they will more than likely accept the default value. If they don't want the default value then they can select a value from the drop-down list.
I built a test sheet which shows the what the sheet should look like when data is filled out in column A and the associated values in column B.
My test is here: https://docs.google.com/spreadsheets/d/1p8sq63S-vSU1FKFLjtr2ZypItN5viXotoZL0Ki2PoQM/edit?usp=sharing
Here is the cobbled together script I was attempting to build (I too find it funny). This is my first attempt to right a Google Script to run on a spreadsheet.
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var aSheet = ss.getActiveSheet();
var aCell = aSheet.getActiveCell();
var aColumn = aCell.getColumn();
var aRow = aCell.getRow();
//var licenseStatus = aSheet.getRange(aRow, aColumn+9).getValue();
// The row and column here are relative to the range
// getCell(1,1) in this code returns the cell at B2, B2
var licenseTypeCell = aSheet.getRange(aRow, aColumn+1);
if (aColumn == 1 && aSheet.getName() == 'Onsite') {
if (isnumber(aCell) && (len(aCell) <= 6)) {
var rule = SpreadsheetApp.newDataValidation().requireValueInList(['ANN','RNW']).build();
licenseTypeCell.setValue("ANN");
licenseTypeCell.setDataValidation(rule);
} else {
var rule = SpreadsheetApp.newDataValidation().requireValueInList(['1DY','RNW','NEW']).build();
licenseTypeCell.setValue("1DY");
licenseTypeCell.setDataValidation(rule);
}
}
}
Any help/guidance would be greatly appreciated.
You are on the right track, few minor changes. Below you will find some new function to be used in your code.
1) getValue() You get your cell using var aCell = aSheet.getActiveCell() i.e the cell that was edited. But to get the value of the cell you will need to do the following aValue = aCell.getValue()
2) isNaN() To check if the aValue (as determined above) is a number or not. You will use a function called isNaN(aValue). Google script uses javascript platform and hence we need to use functions from javascript. This is different from an inbuilt function you use in a google spreadsheet. It returns True if the value is Not A Number(NAN). Hence, we use a not operator(!) to flip the return value, like so
if(!isNaN(aValue))
3) Number of digits There is no len function in google scripts, hence to determine if the number is 6 digits long you can do the following
if(aValue < 1000000)
Your final code will look something like this:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var aSheet = ss.getActiveSheet();
var aCell = aSheet.getActiveCell();
var aColumn = aCell.getColumn();
var aRow = aCell.getRow();
//var licenseStatus = aSheet.getRange(aRow, aColumn+9).getValue();
// The row and column here are relative to the range
// getCell(1,1) in this code returns the cell at B2, B2
var licenseTypeCell = aSheet.getRange(aRow, aColumn+1);
var aValue = aCell.getValue()
if (aColumn == 1 && aSheet.getName() == 'Main') {
if (!isNaN(aValue) && aValue < 1000000) {
var matchCell = aSheet.getRange(aRow, aColumn+3).getValue()
//The above gets value of column D (MATCH or NO MATCH)
if(matchCell == "MATCH"){ //Check if Col D is MATCH
licenseTypeCell.setValue("ANN");
}
else{
var rule = SpreadsheetApp.newDataValidation().requireValueInList(['ANN','RNW']).build();
licenseTypeCell.setValue("ANN");
licenseTypeCell.setDataValidation(rule);
}
} else {
var rule = SpreadsheetApp.newDataValidation().requireValueInList(['1DY','RNW','NEW']).build();
licenseTypeCell.setValue("1DY");
licenseTypeCell.setDataValidation(rule);
}
}
}
Also, note the addition of the following lines to check for col D Value
var matchCell = aSheet.getRange(aRow, aColumn+3).getValue()
//The above gets value of column D (MATCH or NO MATCH)
if(matchCell == "MATCH"){ //Check if Col D is MATCH
licenseTypeCell.setValue("ANN");
}
I have a code that puts a timestamp in when column 1 is edited and then a second timestamp when another column has the word 'collected' input to it. From this I then work out time it took to be collected and use that data. However if someone edits column 1 again it updates the timestamp so I'm looking for a script to allow it to only do it on first edit. Here is my current script;
function onEdit(e) {
var sheet = SpreadsheetApp.getActiveSheet();
if( sheet.getName() == "CC sheet" ) {
//Update timestamp when changed to collected
var range = sheet.getActiveCell();
Logger.log(range.getColumn())
if( range.getColumn() == 7.0 ) { //if we are in the status column...
var nextCell = range.offset(0, 2);
if(range.getValue() == 'Collected')
if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date());
}
//end
}
if(e.source.getActiveSheet().getName() !== 'CC sheet' || e.range.columnStart !== 1) return;
e.range.offset(0, 5).setValue(e.value ? new Date() : null);
}
It is the bottom bit I need to change to only update on first edit. Any help with this would be much appreciated.
replace last row or code with this one:
if (e.range.offset(0, 5).getValue() === '') {
e.range.offset(0, 5).setValue(e.value ? new Date() : null);
}
it's the same 'is empty?' check, as you have in the first part of script.
I'm trying to adapt my inEdit script to give not just a timestamp but also add a "2" in another field,
I thought the following would work but only the date works and it ignores my "2".
What am I missing for both the date and 2 to appear onEdit?
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Sanshiro" ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( r.getColumn() == 6 ) { //checks the column
var nextCell = r.offset(0, -5);
if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date());
nextCell = r.offset(0, 10);
if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue("2");
} }
I don't know if the check if the 'nextcell' is empty is really needed ? you still want to update that cell if a new edit takes place, right ? Anyway, I think you can simplify your script to:
function onEdit(e) {
if (e.source.getActiveSheet()
.getName() !== "Sanshiro" || e.range.columnStart !== 6) return //checks that we're on the correct sheet
e.range.offset(0, -5)
.setValue(new Date());
e.range.offset(0, 10)
.setValue(2);
}
I am using Google Spreadsheets and what I am trying to do is update the cells that contain a timestamp in the Time last Updated column each time I update a cell in the same row.
Is there any way I can achieve that?
Thanks in advance,
not tested but something like this should work. Since you didn't provide any details, you will have to change some variables according to your needs.
function onEdit(e) {
var startCol = 2,
endCol = 10,
tsCol = 11, //this is the column where the timestamp will appear
startRow = 2,
sheetName = 'Sheet1', //this is the name of the sheet you want the script to work on.
curSheet = e.source.getActiveSheet();
//exit script when edits are made another sheet, or in the first row, or before col 2 or after col 10
if (curSheet.getName() !== sheetName || e.range.columnStart < startCol || e.range.columStart > endCol || e.range.rowStart < startRow) return;
curSheet.getRange(e.range.rowStart, tsCol)
.setValue(new Date());
}