Copy one cell to adjacent cell in Google Sheets - google-apps-script

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);
}
}

Related

apps script - search value from sheet1 in array in sheet2 (google sheets)

I'm completely new to apps script and java.
I have a tracker where users insert IDs in col1 sheet1. I need to be able to prevent and alert them whenever their input DOESN'T exists in an array in col2 sheet 2.
so far I've got this, but this is not working for me at all.
var ss = SpreadsheetApp.getActiveSpreadsheet();
function onEdit(e) {
var sheet = ss.getSheetByName("Sheet1")
var so = ss.getSheetByName("Sheet2"); so.activate();
var vltest = sheet.getActiveCell().getValue()
var vlary = so.getActiveCell().getValue()
var r = sheet.getActiveRange().getRow()
var c = sheet.getActiveRange().getColumn();
if(vltest!=="" && c==1 && r>1 && sheet == "Sheet1"){
var data = so.getRange("B1:B").getValues().filter(String).flat()
if(data.indexOf(vlary)=data.lastIndexOf(vlary)){
e.range.setValue("")}
if(data.indexOf(vlary)=data.lastIndexOf(vlary)){SpreadsheetApp.getUi().alert("Alert", "Alert", SpreadsheetApp.getUi().ButtonSet.OK);}}}
Any ideas?
You need to get all values from compare sheet, loop them through and look for match of the value, that onEdit() gives you back. Something like this:
function onEdit(e) {
var ss = SpreadsheetApp.openById('sheet_ID'); //or getActive();
var so = ss.getSheetByName("Sheet2");
// let's say you get all rows from column 1
var compareData = so.getRange(1, 1, so.getLastRow(), 1).getValues();
for (var d = 0; d < compareData.length; d++) {
if (compareData[d] === e.value) {
SpreadsheetApp.getUi().alert("Alert", "Alert", SpreadsheetApp.getUi().ButtonSet.OK)
}
}

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.

Google App Script update cell value in another sheet

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');
}
}
}
}
}

Migrating text formatting from a cell to another cell that references it

In one of the sheets of a google spreadsheet there is a cell which I am referencing in another cell. The text gets copied fine but without any of the formatting. So if I have any bold or italic writing it will show as normal writing in the referenced cell.
I have tried the below script but it's not working as it should. Instead of copying the whole formatting it copies just the cell borders and it copies it to multiple cells below as well(to a total of 7 cell, the target one plus 6 below).
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
var activeSheetName = activeSheet.getName();
var activeCell = activeSheet.getActiveCell();
if ( activeSheet.getName().indexOf("Job ID") != -1 && activeCell.getRow() == 4 && activeCell.getColumn() == 15 ) {
var targetSheet = ss.getSheetByName('Active Jobs');
var jobRowNumber = findJobIdRow();
var sourceCell = activeSheet.getRange(4,1,15,1);
sourceCell.copyFormatToRange(targetSheet, 16, 16, jobRowNumber, jobRowNumber);
}
}
function findJobIdRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var jobID = ss.getActiveSheet().getRange(2,1).getValue();
var column = ss.getSheetByName('Active Jobs').getRange(2,1,ss.getSheetByName('Active Jobs').getMaxRows()-2,1);
var values = column.getValues(); // get all data in one call
for(var ct = 0; ct < values.length-1; ct++){
if(values[ct][0] == jobID){
var ct = ct+2;
break;
}
}
return ct;
}
First, your invocation of getRange may contain an error:
you write
var sourceCell = activeSheet.getRange(4,1,15,1);
but this range is not a single cell, it's a 15-by-1 range starting from A4. The order is (row, column, numRows, numColumns). Perhaps you meant
var sourceCell = activeSheet.getRange(4,15,1,1);
Second, I suggest using copyTo method, which has options that supersede the functionality of "copy...ToRange" methods.
var targetRange = targetSheet.getRange(...);
sourceCell.copyTo(targetRange, {formatOnly: true});

Google Spreadsheet: run script on cell value change

In a spreadsheet I have two sheets, * and Calculator. When I change the value on "*"!B1 (i.e. cell B1 of sheet *), I want to run the script: to change (actually clear) the value of "Calculator"!B3 (i.e. cell B3 of sheet "Calculator").
Here's my code. I created it through Spreadsheet > Tools > Script editor, so it's not an standalone:
The difference between Version 1 and 2 is that in Version 1 the first function is run and the second is missed (vice versa in Version 2), plus one thing I'll detail below.
Version 1
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var languageSheet = ss.getSheetByName("*").getSheetName();
var languageCell = languageSheet.getRange("B1");
var sheets = ss.getSheets()[0];
var languageCellCheck = sheets.getActiveCell();
var cookingMethodSheet = ss.getSheetByName("Calculator").getSheetName();
var cookingMethodCell = cookingMethodSheet.getRange("B3");
var range = e.range;
if (range == languageCell)
cookingMethodCell.setValue("A");
}
//function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var languageCell = ss.getSheetByName("*").getRange("B1");
var sheets = ss.getSheets()[0];
var languageCellCheck = sheets.getActiveCell();
var cookingMethodCell = ss.getSheetByName("Calculator").getRange("B3");
var range = e.range;
if (range == languageCell)
cookingMethodCell.setValue("A");
//}
Version 2
//function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var languageSheet = ss.getSheetByName("*").getSheetName();
var languageCell = languageSheet.getRange("B1");
var sheets = ss.getSheets()[0];
var languageCellCheck = sheets.getActiveCell();
var cookingMethodSheet = ss.getSheetByName("Calculator").getSheetName();
var cookingMethodCell = cookingMethodSheet.getRange("B3");
var range = e.range;
if (range == languageCell)
cookingMethodCell.setValue("A");
//}
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var languageCell = ss.getSheetByName("*").getRange("B1");
var sheets = ss.getSheets()[0];
var languageCellCheck = sheets.getActiveCell();
var cookingMethodCell = ss.getSheetByName("Calculator").getRange("B3");
var range = e.range;
if (range == languageCell)
cookingMethodCell.setValue("A");
}
When I say "Version 1" I mean I changed the value of "*"!B1 from "Something" to "Whatever", and cell "Calculator"!B3 wasn't changed. Then, using Version 2, I tried the same but got the same result (no change in B3).
The idea of having two functions (same for both versions) is because I don't know if using ss.getSheetByName("Calculator").getSheetName(); or directly selecting in as in ss.getSheetByName("*").getRange("B1"); will make a difference. Apparently, it doesn't.
What's and where's the error?
Going by your variable name var languageSheet = ss.getSheetByName("*").getSheetName(); it seems that you expect languageSheet to actually be a sheet object and not a string. That seems to be reaffirmed var sheets = ss.getSheets()[0];
As such you must edit that line to say var languageSheet = ss.getSheetByName("*") and the same goes further on with var cookingMethodSheet = ss.getSheetByName("Calculator")
Now the real problem:
if (range == languageCell)
cookingMethodCell.setValue("A");
this will always return false. You are comparing two different objects. They will never be the same. You need to compare their column and row or A1 notation instead by using something like range.getColumn() and range.getRow() or range.getA1Notation(). Currently it's like you write the number 3 on two pieces of paper and ask if the two pieces of paper are the same thing. They will both have the same value and be comparable, but they will never be the same piece of paper.
Furthermore, going by your code, you are getting the edited range and then you get the active cell which will always be the same cell. So you might as well have the logic be if (1 == 1) or more specifically, because you are comparing to range type objects, it's like writing if (1 == 2)
EDIT: With the things considered in the comments of this answer you are making things more complicated then they need to be. Here is a function that will clear B1:B3 in Calculator only if B1 in * is changed:
function onEdit(e) {
var langName = '*'
var langCell = 'B1'
var curSheet = e.range.getSheet()
if (curSheet.getName() === langName) {
if (e.range.getA1Notation() === langCell) {
var cookingMethodSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Calculator')
var range = cookingMethodSheet.getRange('B1:B3')
range.clear()
}
}
which you can make a little shorter by doing
function onEdit(e) {
if (e.range.getSheet().getName() === '*') {
if (e.range.getA1Notation() === 'B1') {
SpreadsheetApp
.getActiveSpreadsheet()
.getSheetByName('Calculator')
.getRange('B1:B3')
.clear()
}
}
The indentation is there only so the line is not too long.