This question already has answers here:
Determining the last row in a single column
(30 answers)
Closed last year.
I saw another thread Here with a solution to my start stop issue except it is written to find the last cell in the whole book. I need this for just rows A (for start), and row B (for stop) as I will have other data on the sheet.
I also need to be able to do the same function for multiple sheets... so start and stops just for that sheet.
Here is the current code I am using...
I believe your goal is as follows.
When you run the script of startTime(), you want to put new Date() to the cell of the next row of the last row of the column "A".
When you run the script of stopTime(), you want to put new Date() to the cell of the next row of the last row of the column "B".
You want to run the script for the specific sheets you expect.
getLastRow returns the last row of all columns. When you want to retrieve the last row of the specific column, it is required to check it using a script instead of the method of getLastRow. So, from your sample Spreadsheet shown in your image, how about the following sample script?
Sample script:
const sheetNames = ["Line1",,,]; // Please set the sheet names you want to run the script.
// Ref: https://stackoverflow.com/a/44563639
Object.prototype.get1stNonEmptyRowFromBottom = function (columnNumber, offsetRow = 1) {
const search = this.getRange(offsetRow, columnNumber, this.getMaxRows()).createTextFinder(".").useRegularExpression(true).findPrevious();
return search ? search.getRow() : offsetRow;
};
function startTime() {
const sheet = SpreadsheetApp.getActiveSheet();
if (!sheetNames.includes(sheet.getName())) return;
const row = sheet.get1stNonEmptyRowFromBottom(1) + 1;
sheet.getRange(row, 1).setValue(new Date());
}
function stopTime() {
const sheet = SpreadsheetApp.getActiveSheet();
if (!sheetNames.includes(sheet.getName())) return;
const row = sheet.get1stNonEmptyRowFromBottom(2) + 1;
sheet.getRange(row, 2).setValue(new Date());
}
Note:
If you don't want to put the value to the column "B" when the column "A" is blank, please modify sheet.getRange(row, 2).setValue(new Date()); in stopTime() as follows.
const range = sheet.getRange(row, 2);
if (range.offset(0, -1).isBlank()) return;
range.setValue(new Date());
Reference:
Related thread
Determining the last row in a single column
Related
I am looking for a macro that can help move a row of a sheet to the bottom of it once it passes a certain date. Basically this will be used for a meeting tracker and I'm trying to find a way to automatically move meetings to a "Completed" section once the date (located on Column F) passes.
I've created macros before to move things between sheets, but I'm unfamiliar with how to move things on the same sheet. Would anyone be able to help?
Here's the sheet: https://docs.google.com/spreadsheets/d/1EPueop9bdky_J8VgpFdSUzzsMRieRUreeCRIy18ScTY/edit#gid=0
I would like to move rows based on the date in Column F. Once it passes I would like it to move to the "Completed" section of the sheet. This is an active spreadsheet so the row "Completed" it's on could change as meetings are being added.
function moveActiveRowToBottom() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const r = sh.getActiveRange().getRow();
const vs = sh.getRange(r,1,1,sh.getLastColumn()).getValues();
sh.getRange(sh.getLastRow() + 1, 1, vs.length, vs[0].length).setValues(vs);
sh.deleteRow(r);
}
I believe your goal is as follows.
You want to check the date of column "F" of the sheet. When the date of column "F" is smaller than today, you want to move the row to the last row.
You want to achieve this in the same sheet in a Google Spreadsheet. And, the sheet has a row of "Completed" in column "A", you want to check the date of the above rows of the "Completed" row.
In this case, how about the following sample script?
Sample script:
Please copy and paste the following script to the script editor of Spreadsheet, and save the script. When you use this script, please run the function of myFunction().
function myFunction() {
const sheet = SpreadsheetApp.getActiveSheet(); // or const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet 1");
const row = sheet.getRange("A4:A" + sheet.getLastRow()).createTextFinder("Completed").findNext().getRow();
const now = new Date().getTime();
const moves = sheet.getRange("F4:F" + (row - 1)).getValues().reduce((ar, [f], i) => {
if (f && f.getTime() < now) {
const r = i + 4;
ar.push(sheet.getRange(`A${r}:F${r}`));
}
return ar;
}, []).reverse();
const len = moves.length;
if (len == 0) return;
const lastRow = sheet.getLastRow();
moves.forEach((r, i) => sheet.moveRows(r, lastRow - i + len - 1));
}
When this script is run, the column "F" of the rows from 4 to the "Completed" row is checked. And, when there are moving rows, the rows are moved to the last row of the sheet.
Note:
This sample script was tested using your provided Spreadsheet. When you change the Spreadsheet and/or your actual Spreadsheet is different from your provided Spreadsheet, this script might not be able to be used. Please be careful about this.
When I saw your sample Spreadsheet, it seems that the sheet name is Sheet 1. If you want to use the sheet using the sheet name, please be careful about this.
References:
reduce()
forEach()
moveRows(rowSpec, destinationIndex)
Is it possible to:
have a checkbox (J2) copy a result (J3) and paste contentsOnly into another cell
(D13)
to then have the same checkbox copy a different result (shown in J3) and paste contentsOnly into the cell below the previous (D14).
lastly, loop step 2
.
Some of the searching and tried modifications:
var Col="A"; //Column that will find the last row not empty, can be assigned as parameter
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet2');
var yourRange = sheet.getRange(Col + 1).offset(sheet.getLastRow()-1, 0); //+1 spare 1 row after last row
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 4);
Also looking at this link to try and Determining the last row in a single column and continue.
.
Please find editable sheet below:
Trial - Checkbox to Paste by last row in Column D
Modification points:
In your situation, how about using this sample script? Ref When this sample script is used, the last row of the specific column can be retrieved. By reflecting this script in your script, I thought that your goal might be able to be achieved.
And, about your script, I thought that when the event object is used, the process cost can be reduced. Ref
When these points are reflected in your script, how about the following modification?
Modified script:
function onEdit(e) {
// Ref: https://stackoverflow.com/a/44563639
Object.prototype.get1stNonEmptyRowFromBottom = function (columnNumber, offsetRow = 1) {
const search = this.getRange(offsetRow, columnNumber, this.getMaxRows()).createTextFinder(".").useRegularExpression(true).findPrevious();
return search ? search.getRow() : offsetRow;
};
var {range} = e;
var sheet = range.getSheet();
if (sheet.getSheetName() != "Trail - Copy & Paste" || range.getA1Notation() != "J2" || !range.isChecked()) return;
var lastRowOfColumnD = sheet.get1stNonEmptyRowFromBottom(4);
lastRowOfColumnD = lastRowOfColumnD > 12 ? lastRowOfColumnD : 12;lastRowOfColumnD = lastRowOfColumnD > 12 ? lastRowOfColumnD : 12;
sheet.getRange("J3").copyTo(sheet.getRange(lastRowOfColumnD + 1, 4), { contentsOnly: true });
}
In this modification, when the checkbox of "J2" of "Trail - Copy & Paste" sheet is checked, the script works. And, the value of "J3" is copied to the next row of the last row of column "D".
From your reply of however, once all the data in cell D13:D are cleared, having a hard time doing the first copy and paste into D13. Do you know of any workaround for this?, I understood that you wanted to set the initial row number of 13. So, I modified abve script.
In Google Sheets, I want to create a macro that will automatically populate a column in each row when another column in that row is manually filled. The autofilled cell will use a formula that takes a chunk of the information (date) that's been entered manually and use a formula to concatenate it with a random number in order to create a unique ID. After inserting and executing the formula, the macro needs to copy and then paste "values only" the result of that formula. The point is to automatically create a stable ID in response to a triggering event (entry of date in row).
In pseudocode, here's the process I'd like the macro to execute:
when (date in yyyy-mm-dd format entered into A[i]) {
fill B[i] with =CONCATENATE(SUBSTITUTE(LEFT(A[i], 7), "-", ""),RANDBETWEEN(0,1000000000));
copy B[i];
PASTE_VALUES B[i] in B[i];
}
Apologies if I've overlooked a previous answer that solves this problem. I'm not new to coding, but I am new to coding in Google Sheets and am not sure what terms or phrases to use to describe what I'm after.
I believe your goal is as follows.
For example, when a value with the format of yyyy-mm-dd is put to the cell "A1", you want to put the formula of =CONCATENATE(SUBSTITUTE(LEFT(A1, 7), "-", ""),RANDBETWEEN(0,1000000000)) to the cell "B1".
You want to fix the value of the formula as the value.
You want to achieve this using OnEdit trigger.
Added: You want to put the value to the column "B", when the column "B" is empty.
In this case, how about the following sample script?
Sample script:
Please copy and paste the following script to the script editor of Spreadsheet, and save the script. And, please set the sheet name you want to use. When you use this script, please put the value with the format of yyyy-mm-dd to the column "A", by this, the script is run.
function onEdit(e) {
const sheetName = "Sheet1"; // Please set the sheet name.
const range = e.range;
const sheet = range.getSheet();
const [a, b] = range.offset(0, 0, 1, 2).getDisplayValues()[0];
if (sheet.getSheetName() != sheetName || range.columnStart != 1 || !/\d{4}-\d{2}-\d{2}/.test(a) || b) return;
const dstRange = range.offset(0, 1);
dstRange.setFormula(`=CONCATENATE(SUBSTITUTE(LEFT(${range.getA1Notation()}, 7), "-", ""),RANDBETWEEN(0,1000000000))`);
SpreadsheetApp.flush();
dstRange.copyTo(dstRange, { contentsOnly: true });
}
Reference:
Simple Triggers
This is the script I came up with:
/** #OnlyCurrentDoc */
function onEdit(e) { //Runs every time the sheet is edited
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1'); //Change this to whatever your sheet is named
var inputCol = sheet.getRange('A1'); //Change this to whatever column the date is going to be entered
//This is the range that will be checked. Slightly redundant, but makes it easier to reuse this script without needing to retype every variable
var myRange = inputCol;
//Get the row & column indexes of the active cell
var row = e.range.getRow();
var col = e.range.getColumn();
//Check that your edited cell is within the correct column
if (col == myRange.getColumn()) { //This runs only if a value is entered into the column defined in 'inputCol'
if(sheet.getRange(e.range.getA1Notation()).getValue() == '') {return}; //If the edited cell is empty (ie the date is deleted, nothing happens)
if(row == 1) {return} //If the header is changed, nothing happens
let codeCell = sheet.getRange('B'+row); //Change to the column that will store the generated code value
codeCell.setValue('=CONCATENATE(SUBSTITUTE(LEFT(A'+row+', 7), "-", ""),RANDBETWEEN(0,1000000000))');
let hardValue = codeCell.getValue(); //Gets the value from the formula you just entered
codeCell.setValue(hardValue); //Replaces the formula with just the resulting value
};
}
Comments are included to explain everything that is happening. Linked below is the spreadsheet I used to test this. It is set to allow editing, so feel free to use it to test the script yourself.
https://docs.google.com/spreadsheets/d/1UONgRPBEbxn8CQeiRSPS4eFKHjh4ae8hXGYn6ImHxeI/edit?usp=sharing
Hope this helps!
This question already has an answer here:
Why do we use SpreadsheetApp.flush();?
(1 answer)
Closed 1 year ago.
I'm struggling to understand an issue I'm having with row indexes being out of bounds.
Using Apps Script I'm copying a range from one sheet to another. The sheet that is being copied to originally contains one empty row, and then I am copying two rows of data to it - this works fine.
I then am trying to copy the row heights from the source sheet to the destination sheet and this is where I run into the issue. The first row works fine but then when it gets to the 2nd row it gives me an out of bounds error. If I change the destination sheet so that it starts off with 2 empty rows then I do not get this error.
I also do not get the error if I first run the copy function and then separately run the change row height function after.
To me it seems like Apps Script is storing the destination sheet before the additional row is added and then when I try to change the height of the 2nd row it thinks it doesn't exist? Does anyone know a way around this.
What's also odd is if I run getLastRow() on the destination sheet right before changing the row heights it returns 2, so somewhere it knows there are 2 rows.
Here is my function that copies a named range and then the row heights:
const ss = SpreadsheetApp.getActiveSpreadsheet();
const namedRanges = [['namedRange', 24, 2]] //Range name, number of columns, number of rows
function copyRange(sheetName, rangeName, destRow, destCol) {
const sourceRange = ss.getRangeByName(rangeName);
const sourceSheet = sourceRange.getSheet();
const destSheet = ss.getSheetByName(sheetName);
for (let i = 0; i < namedRanges.length; i++) {
if (namedRanges[i][0] === rangeName) {
var rangeIndex = i;
break;
}
}
const destRange = destSheet.getRange(destRow, destCol, namedRanges[rangeIndex][2] - 1, namedRanges[rangeIndex][1] - 1);
sourceRange.copyTo(destRange)
for (let i = 0; i < namedRanges[rangeIndex][2]; i++) {
let row = sourceRange.getRow() + i;
let height = sourceSheet.getRowHeight(row);
destSheet.setRowHeight(destRow + i, height);
}
}
Fix was to add SpreadsheetApp.flush() between copying the range and changing the row heights as per TheMaster's comment above.
If you are just copying from a named range to a named range in which the latter only need be a single cell. Then this would suffice.
function myfunk() {
const nrl = [{srg = 'srg1',drg: 'drg1'},{srg = 'srg2',drg: 'drg2'}];
nrl.forEach(obj => {
obj.srg.copyTo(obj.drg)
});
}
This can only occur in the same spreadsheet and the sheet names are included in the definition of the named ranges.
I would like to place text inside the first empty row of a specific column. I've tried following the link Faster way to find the first empty row in a Google Sheet column
and I believe that instead of using return I should use something different as I want to place text inside that column instead of going to that column.
I tried the code to place text but I can only do that for a specific row and column
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getRange(1,3);
cell.setValue('hello');
How do I implement the above to the code below i.e. once it iterates finish, place text in the first empty row of column C
var sheet = SpreadsheetApp.getActiveSheet();
var column = sheet.getRange('C:C');//specific column
var values = column.getValues();//get all data in that column
var row = 0;
for (var row=0; row<values.length; row++) {
if (!values[row].join("")) break;
}
return ('hello');
How about this modification?
Modification points:
In your script, when the for loop is finished, row is the 1st empty row number. This value can be used like sheet.getRange(row + 1, 3).setValue('hello');.
When C:C is modified to 'C1:C' + sheet.getLastRow(), the search range can be reduced.
When above points are reflected to your script, it becomes as follows.
Modified script:
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var column = sheet.getRange('C1:C' + sheet.getLastRow()); // Modified
var values = column.getValues();
var row = 0;
for (row=0; row<values.length; row++) {
if (!values[row].join("")) break;
}
sheet.getRange(row + 1, 3).setValue('hello'); // Added
}
When you run the modified script, hello is put to the column "C" of the 1st empty row in the active sheet.
Other pattern:
As other method, in your case, you might be able to use getNextDataCell as follows.
SpreadsheetApp
.getActiveSheet()
.getRange('C1')
.getNextDataCell(SpreadsheetApp.Direction.DOWN)
.offset(1, 0)
.setValue('hello');
Note:
If you want to put the value to the last row of the column "C", please test the following script.
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(sheet.getLastRow() + 1, 3).setValue('hello');
References:
getRange(row, column)
setValue(value)
getNextDataCell(direction)
I think You don't need to check the row whether empty or not in spreadsheet before storing
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(A:A).setValue("some_data");
by this using this you can simply store the value in first empty row in sheet. Please check and repond me after trying