Google App Script update cell value in another sheet - google-apps-script

I'm a little stuck on this one. I'm trying to find the corresponding row and update the last column in another google spreadsheet after updating the first column of another spreadsheet.
When the user selects "Restocked" in ColA of spreadsheet X , I need to lookup the ID value in ColB on another sheet (Y). Then I need to access spreadsheet Y, find the row that contains that same ID. Access the last column or columnAZ (52) and change the cell value to "Restocked".
Here is what I have so far...
function restockComplete(){
var s = SpreadsheetApp.getActiveSpreadsheet();
if( s.getName() == "Restock Queue"){
var r = s.getActiveCell();
if ( r.getColumn() == 1 && r.getValue() == "Restocked"){
var nextCell = r.offset(0, 1);
var buybackId = nextCell.getValue();
// Opens SS by its ID
var ss = SpreadsheetApp.openById("xxxxxxxxxxxxxxxSheetIDHerexxxxxxxxxxx");
var sheet = ss.getSheetByName('NameOfSheetHere'); // Name of sheet
// var range = sheet.getRange(1,1); // Gets Column 1 Cell 1 value
//var data = range.getValue();
var data = sheet.getDataRange().getValues();
//var buyback = sheet.getRange(buybackId).getValue();
for(var i = 0; i<data.length;i++){
if(data[i][1] == buybackId){ //[1] because column B
Logger.log((i+1))
i.offset(0, 52).setValue('Restocked');
return i+1;
}
}
}
}
};

You're close, save for one error. Right now, to test for the sheet name, you have to actually get the sheet. I would do the following to fix the immediate problem:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet() // call this for the active sheet
...
You also had an error in your loop setting the value:
for(var i = 0; i<data.length;i++){
if(data[i][1] == buybackId){ //[1] because column B
// Get the range of the cell, not the index.
sheet.getRange((i+1), 1).setValue('Restocked');
}
}
...
Rename your secondary sheet from ss to something else to avoid a conflict.
Beyond this fix, there are some changes I'd recommend making to make the script more efficient for your users. Rather than look for the active cell, you can use the onEdit simple trigger with an e event object. This will allow your script to modify cells regardless of where the active cell is.
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var s = ss.getActiveSheet();
if( s.getName() == "Restock Queue"){
if ( (e.range.getColumn() == 1.0) && (e.range.getValue() == "Restocked") ){
var nextCell = e.range.offset(0, 1);
var buybackId = nextCell.getValue();
var ss2 = SpreadsheetApp.openById('xxx');
var sheet = ss2.getSheetByName('NameOfSheetHere'); // Name of sheet
var data = sheet.getDataRange().getValues();
for(var i = 0; i<data.length;i++){
if(data[i][1] == buybackId){ //[1] because column B
// Get the range of the cell, not the index.
sheet.getRange((i+1), 52).setValue('Restocked');
}
}
}
}
}

Related

Combine two functions that must work one after another (with trigger)

I have two working functions. One of them is myFunction with a trigger. Is protects the row of the cell when any information is entered in this cell in Column4.
function myFunction(e) {
const sheetNames = ['Sheet1', 'Sheet2', 'Sheet3']; // Please set the sheet names you want to run the script.
const range = e.range;
const sheet = range.getSheet();
const value = range.getValue();
const row = range.getRow();
if (!sheetNames.includes(sheet.getSheetName()) || range.getColumn() != 4 || row == 2 || value == "") return;
const p = sheet.getRange(`B${row}:D${row}`).protect();
const owner = Session.getActiveUser().getEmail();
p.getEditors().forEach(f => {
const email = f.getEmail();
if (email != owner) p.removeEditor(email);
});
}
Another function is an onEdit function. It adds date in Column1 when I enter information in Column4. The date appears in the same row with the cell in Column4.
function onEdit() {
var colToCheck = 4;
// Offset from the input [row, column]
var dateOffset = [0, -3];
// Sheets to proceed on
var sheetNames = ['Sheet1', 'Sheet2', 'Sheet3'];
var sheet = SpreadsheetApp.getActive().getActiveSheet();
var name = sheet.getName();
if (sheetNames.indexOf(name) > -1) {
var cell = sheet.getActiveCell();
var col = cell.getColumn();
if (col == colToCheck) {
var dateTimeCell = cell.offset(dateOffset[0], dateOffset[1]);
dateTimeCell.setValue(new Date());
}
}
}
How these two functions can be combined in one sheet?
I just added two separate functions to one sheet: the one with trigger and the one onEdit as two different codes. And they work as I need. So, we do not need to combine them somehow. They just work one after another. First, the one onEdit function works, and as it adds info to the necessary cell, the function with trigger starts working.

Insert Timestamp when copy/paste whole row and value inserts/edits in Column C in google sheets

I tried inserting timestamp when a row is being copied and data inserts or edits in Column C same row cell, but it works only on manual entry, not on copy-paste.
Please suggest to me what I am missing or doing wrong.
function onChange() {
var s = SpreadsheetApp.getActiveSheet();
var sName = s.getName();
var r = s.getActiveCell();
var row = r.getRow();
var ar = s.getActiveRange();
var arRows = ar.getNumRows()
// Logger.log("DEBUG: the active range = "+ar.getA1Notation()+", the number of rows = "+ar.getNumRows());
if( r.getColumn() == 3 && sName == 'Sheet1') { //which column to watch on which sheet
// loop through the number of rows
for (var i = 0;i<arRows;i++){
var rowstamp = row+i;
SpreadsheetApp.getActiveSheet().getRange('F' + rowstamp.toString()).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm"); //which column to put timestamp in
}
}
}//setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm:ss");
Use getLastColumn() to check whether column C is included in the pasted range.
Use getNumRows() to get the number of rows your copied range has, and so add the timestamp to all these rows.
No need to used an installed onChange() for this, a simple onEdit() is enough.
I'd also suggest to use event object in order to get information on which range was edited (even though this way you won't be able to fire this successfully from the script editor).
Edit: if you want to remove the timestamp when the range is cleared, you can just check that's the case, using every, or some, and clearContent if that's the case.
Code snippet:
function onEdit(e) {
var s = SpreadsheetApp.getActiveSheet();
var r = e.range;
var firstRow = r.getRow();
var numRows = r.getNumRows();
var firstCol = r.getColumn();
var lastCol = r.getLastColumn();
if((firstCol <= 3 || lastCol >= 3) && s.getName() == 'Sheet1') {
var emptyRange = r.getValues().every(row => row.every(value => value === ""));
var destRange = s.getRange(firstRow, 6, numRows);
if (emptyRange) destRange.clearContent();
else {
var dates = new Array(numRows).fill([new Date()]);
destRange.setValues(dates).setNumberFormat("MM/dd/yyyy hh:mm");
}
}
}
The following script will create timestamps starting from column F until the last column when you copy the row.
I think you are looking for this:
function onEdit(e) {
const startCol = 6; // column F
const s = e.source.getActiveSheet();
const sName = s.getName();
const ar = e.range;
const row = ar.getRow();
const arColumns = ar.getNumColumns();
const arRows = ar.getNumRows();;
if( sName == 'Sheet1') {
const rng = s.getRange(row,1,arRows,s.getMaxColumns());
check = rng.getValues().flat().every(v=>v=='');
if(check){
rng.clearContent();
}
else{
s.getRange(row,startCol,arRows,s.getMaxColumns()-startCol+1).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm");
}
}
}
Note:
Again, onEdit is a trigger function. You are not supposed to execute it manually and if you do so you will actually get errors (because of the use of the event object). All you have to do is to save this code snippet to the script editor and then it will be triggered automatically upon edits.

Copy data from one spreadsheet to another onchange

Pardon me as I am fairly new to this and may be missing something easy.
I have a spreadsheet that I create data from a template, run a script over it to create forms which become user tasks. The edit URL from the form is used to complete the task and it records on the master sheet (Sheet2) with the status, attachments, data stamp, and email address. From there I am trying to create a list of tasks that need approvals from my master sheet to another sheet (LOG) on a different spreadsheet but I am having issues with openByID for my target spreadsheet. It says it is undefined. I can get this to work in sheets in the same spreadsheet but I would like it in a different spreadsheet if possible. This is all done onChange of Sheet2 when status changes to yes and only for specific tasks (Verification Report, Maintenance Memo, Check Report)
function onChange() {
// moves a row from one sheet to another sheet when a value is entered in a column and another column has specific values
var columnNumberToWatch = /* column D */ 4; // column A = 1, B = 2, etc.
var valueToWatch = "yes";
var sheetNameToMoveTheRowTo = "LOG";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet2");
var cell = sheet.getActiveCell();
var activeRow = cell.getRow();
var taskCheck=sheet.getRange(activeRow, 2);
var target = SpreadsheetApp.openByID("my spreadsheet id");
var targetSheet = target.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
if (sheet.getName() != sheetNameToMoveTheRowTo &&
cell.getColumn() == columnNumberToWatch &&
cell.getValue().toLowerCase() == valueToWatch &&
(taskCheck.getValue() == "Verfication Report" || taskCheck.getValue() == "Maintenance Memo" || taskCheck.getValue() == "Check Report"))
{
sheet.getRange(cell.getRow(), 1, 1, sheet.getLastColumn()).copyTo(targetRange);
}
}

If AND statements in google script to move data to another sheet based on change in one cell and value in another

OK, I'm fairly new at doing this. I have a google spreadsheet that I populate and then run a script to create forms are created to complete tasks. My end users mark the task as completed. I am wanting entries in the spreadsheet that change to yes AND are Validate tasks to copy to another sheet (Log). I can get the entries to copy if I just have a watcher for yes but am having problems putting the other if statement for the task in there. Here is what I have for a test...
function onChange() {
// moves a row from any sheet to an archive sheet when a magic value is entered in a column
var columnNumberToWatch = /* column D */ 4; // column A = 1, B = 2, etc.
var valueToWatch = "yes";
var sheetNameToMoveTheRowTo = "LOG";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet2");
var cell = sheet.getActiveCell();
if ( sheet.getName() != sheetNameToMoveTheRowTo && cell.getColumn() == columnNumberToWatch
&& cell.getValue().toLowerCase() == valueToWatch) {
if (cell.getColumn() == 2 && cell.getValue() == "Validate") {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(cell.getRow(), 1, 1, sheet.getLastColumn())
.copyTo(targetRange);
}
}
}
It looks like you are trying to watch two separate locations with the same cell variable. You start by initializing cell as the active cell, then check that the column is #4, then in the second if statement you use cell to getColumn 2.
Maybe create a new set of variables to use for the validation check:
var activeRow=cell.getRow();
var valCheck=sheet.getRange(activeRow, 2);
then the if statement changes to:
if (valCheck.getValue() == "Validate") {

Copy one cell to adjacent cell in Google Sheets

I have a formula in column Y. Because of the nature of the formula, I want to copy the contents of the data in column Y when the formula gets calculated, into column Z (onEdit). The code I have so far does not copy any data into the adjacent cell and does nothing when executed:
function onEdit(CopyCourse){
if(CopyCourse.source.getActiveSheet().getName() == "Sheet1" ) {
var actcell = CopyCourse.source.getActiveCell();
var col = CopyCourse.source.getActiveCell().getColumn();
if(col == 25) {
var calcourse = CopyCourse.range.offset(0,1);
//if(calcourse.getValue() == "" && CopyCourse.value != "No") {
var course = CopyCourse.actcell.getValue();
calcourse.setValue(course);
//}
}
}
}
Newer attempt, again no action on the spreadsheet:
function onEdit(e){
var r = e.range();
var o = e.oldValue();
var n = e.range().offset(0,1);
n.setValue(o);
}
This is what I came up with. It works if I enter the formula in each individual cell, however, if I do a copy down, it only copies over the first cell.
function onEdit(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var row = e.source.getActiveCell().getRow();
var col = e.source.getActiveCell().getColumn();
if(col == 25){
var course = e.source.getActiveCell().getValue();
var cell = sheet.getRange(row,col+1);
cell.setValue(course);
}
}