Google Sheet Copy Column Data On Edit - google-apps-script

I had entered a formula in column B of the Google Sheet (link given below) which will generate number if I enter data in Column C.
I want to design a script which will run when data is entered in column C and the script will copy the number generated in column B in column A.
https://docs.google.com/spreadsheets/d/1kfa9pkItGQGaWWD_L8opR9w-MZnWxA2qfBTmNYp0wmg/edit?usp=sharing
Any help on above will be appreciated.

Issue:
If I understand you correctly, you want a script to do the following:
Fire every time column C is edited.
On the edited row, copy the value from column B to column A.
Solution:
In that case, you can use a simple onEdit trigger and the corresponding event object, like this (check inline comments):
function onEdit(e) {
const range = e.range; // Edited range, from event object
if (range.getColumn() === 3) { // Check edited column is C
const b = range.offset(0,-1).getValue(); // Get value from B
if (b !== "") { // Check B is not empty
range.offset(0,-2).setValue(b); // Set value in A
}
}
}

Related

Google Sheets - Read only column that i can copy as well

I have a Google Sheet that I gave editor permissions for a few people that can edit the data.
inside this sheet, I have a column (column B, WEEKDAY) that I want to display as a read-only value according to the value from another column (column A, holding a date value) of the same row.
for example if value of column A is Feb 14th, 2022 then automatically I see value of "Monday" on column B.
in order to prevent mistakes by my editors, I set column B as read-only using the protected range feature.
but, my problem - once I set this protection, they can't copy the entire row to another row, or delete the entire row, as column B is protected.
What is the correct way to solve my need?
using Apps script is possible as well for me.
meanwhile, I changed the protected range from error to warning as I don't have a better solution for now.
I am using ARRAYFORMULA in cell B1, but users can ignore it and manually override the value of B7 (as an example) instead of the formula value. if they do such manual override they get an error on B1 "Array result was not expanded because it would overwrite data in B7.". this is the reason I was looking to set column B as read-only so users can not manually override the formula value.
Issue:
You are using an ARRAYFORMULA on B1 which populates several cells in column B.
You want users to be able to copy and delete rows.
You want users to be unable to edit values in column B (since that would mess with the ARRAYFORMULA).
Solution:
Use an onEdit trigger which does the following every time a user edit a spreadsheet cell:
Check whether the user has permission to edit column B, using Session.getActiveUser() (the list of users who have permissions is defined in the script itself, and it may well be empty).
If the user has permission, check whether the edited cell is in the protected range (B2:B), using the event object.
If the edited cell is in that range, remove any values in that range, using Range.clearContent().
Regarding the cell B1, which contains the formula, I'd protect it conventionally via Sheets editor (ref).
Code sample:
const EDITORS = ["your_editor#domain.com"]; // Users who can edit column B
const SHEET_NAME = "Sheet1"; // Change accordingly
const PROTECTED_COL = 2; // Column B
const FIRST_ROW = 2; // Header row is protected conventionally
function onEdit(e) {
const userEmail = Session.getActiveUser().getEmail();
if (!EDITORS.includes(userEmail)) {
const range = e.range;
const sheet = range.getSheet();
if (sheet.getName() === SHEET_NAME && range.getColumn() === PROTECTED_COL && range.getRow() >= FIRST_ROW) {
sheet.getRange(FIRST_ROW, PROTECTED_COL, sheet.getLastRow()-FIRST_ROW+1).clearContent();
}
}
}
Note:
Make sure you modify EDITORS and SHEET_NAME according to your preferences.

Google Apps Script - How to get clipboard column number

Goal: When a user pastes a value to a cell, I want the script to check whether or not the copied value is from the same column or not.
Problem: Oftentimes, the user copies a cell from a different column and pastes in a cell that's under another column. This causes some problems for this particular sheet, so I want to be able to have the script check if the clipboard’s copied value's column number (or letter) is the same with the column of where the user is trying to paste it.
Example:
Scenario A: User copied a cell from A1 and attempts to paste it to B2 (either by mistake or intentionally)
If statement check: Check if the user’s clipboard copied value’s column number (or letter) is equal to 2 (if by letter: B).
Result: Since the copied column number is 1 and editing column number is 2, the script will show an error message to refuse the editing.
Scenario B: User copied a cell from A1 and attempts to paste it to A2
If statement check: Check if the user’s clipboard copied value’s column number (or letter) is equal to 1 (if by letter: A).
Result: Since the copied column number is 1 and editing column number is also 1, the script will allow the user to pates the value to A2.
Here's my attempt: I thought it would make sense to use the onEdit function to compare
function onEdit(e) {
const range = e.range;
const source = e.source;
const sheetName = source.getActiveSheet().getName();
const row = range.getRow();
const column = range.getColumn();
const editedRangeValue = range.getValue();
// Call the copyPrevention function
copyPrevention(sheetName, range, row, column, editedRangeValue);
}
function copyPrevention(sheetName, range, row, column, editedRangeValue) {
const headerRowNum = 12;
if (sheetName == 'Status' && row > headerRowNum && editedRangeValue != '') {
// row variable: This is to ensure the editing will only apply if the user tries to edit after row 12 (headerRow).
if (column == "") { // The "" is just a placeholder. If this is even possible, I would like to compare user's editing column number & their clipboard column number. And if the column numbers are the same, then I'd like the script to continue the execution without throwing any errors.
range.setValue(editedRangeValue);
} else if (column != "") { // The "" is just a placeholder. I would like to compare user's editing column number & their clipboard column number. And if the column numbers are not the same, then I'd like the script to throw an error and not let the user edit the cell.
const statusSheetUi = SpreadsheetApp.getUi();
statusSheetUi.alert("You're pasting in the wrong column!");
}
}
}
I have a feeling that this isn't possible, however wanted to check.
Thank you!

How to Copy Paste Value in Column U cell based on input made in Column C

As a default Column B is equal to Column U. I'd like to find a macro that copies the value in Column U (e.g. U2) and pastes it as a value in the same cell (U2) if a value is inputted into cell C3 (one row below the U2 cell). Please see the example below, where if I enter GHI123 in cell C3, CD must be copied and pasted in cell U2.
https://docs.google.com/spreadsheets/d/1wZFh8IW6SLkOxNBSyUaDapOnMm2cJwxjZ7KFA79MKnw/edit#gid=0
You can achieve this with the following Apps Script
function onEdit(e) {
var row = e.range.getRow();
var column = e.range.getColumn();
if (column == 3){
cellToEdit = 'U' + (row - 1);
dataToPaste = SpreadsheetApp.getActiveSheet().getRange(cellToEdit).getDisplayValue()
SpreadsheetApp.getActiveSheet().getRange(cellToEdit).setValue(dataToPaste);
}
The getDisplayValue() method allows you to read the displayed value of a cell after any script evaluation. You can find the reference for this method here.

Google app script to copy column values to a different sheet

I am trying to write a google app script so I can copy a few columns (C and D) from my main report sheet to a different sheet, based on the value of column M if that's equal to 0.
As shown in the pic below:
So I want to copy the "Name" and "Variety" columns into another sheet where the "Germination %" column is 0.
It can be a time based trigger, that runs after every 2 hours or onEdit also. I was trying to make it a script using OnEdit, as shown below:
function onEdit( e ){
var sheetFrom = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("germination");
var sheetTo = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("watering");
var data = sheetFrom.getDataRange().getValues();
var target = new Array();// this is a new array to collect data
for(n=0;n<data.length;++n){ // iterate in the array, row by row
if (data[n][12]=="0"){ // if condition is true copy the whole row to target
target.push(data[n]);// copy the whole row
}//if
}//for
//Paste to another sheet from first cell onwards
sheetTo.getRange(1,1,target.length,2).setValues(target);
}
But I am getting errors on this "Incorrect range width, was 15 but should be 2 (line 25, file "Code")"
Line 25 is "sheetTo.getRange(1,1,target.length,2).setValues(target)"
Thanks in advance.
In the getRange(1,1,target.length,2) method you're specifying it to select only 2 columns, change it to getRange(1,1,target.length,target[0].length) to select the array length of columns.
Update:
To write only the C and D, change the target push() to:
target.push( [[data[n][2], data[n][3]] )

Google Script to copy specific columns from one sheet to another sheets last row onEdit

I am looking for some help on google app scripting. Currently I have a spreadsheet that has 3 sheets. First sheet is data that comes from a google form. Second sheet is an "open" tab and third is a "closed" tab.
When data comes into the spreadsheet from the form it has only the columns that the form has. The "open" sheet has a combination of data from the form (sheet 1) and some additional cells to add more information to by me and not the person submitting the form. Because of this column miss-match I cannot just copy a whole row from sheet 1 to sheet 2. This also needs to be done onEdit trigger. So when an edit trigger fires, I want to store that rows data into memory and then copy column B to the last row of tab 2, column C. Column C > E, column D > B. etc..
How would I store the whole row into memory (an array I presume), and then copy only specific cells, in a specific order into the last row of a different sheet?
Hope that makes sense :-/
As you said, you'll have to use arrays to get data and write it back to another sheet in your selected order.
This is pretty basic manipulation and there are many ways to achieve it.
One way that is very easy to understand is as follow :
get row data in an array
pick up each value one by one and store in another array
write back to the last row +1 on another sheet.
Note that arrays are indexed starting from 0 , rows and columns start from 1 and A so you'll have to do some math !
function copyRow(){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var rowIdx = sheet.getActiveRange().getRowIndex();
var rowValues = sheet.getRange(rowIdx,1,1,sheet.getLastRow()).getValues();
Logger.log(rowValues);
var destValues = [];
destValues.push(rowValues[0][0]);// copy data from col A to col A
destValues.push(rowValues[0][2]);// copy data from col C to col B
destValues.push(rowValues[0][1]);// copy data from col B to col C
destValues.push(rowValues[0][3]);// copy data from col D to col D
// continue as you want
var dest = ss.getSheets()[1];//go on chosen sheet (here is the 2cond one)
dest.getRange(dest.getLastRow()+1,1,1,destValues.length).setValues([destValues]);//update destination sheet with selected values in the right order, the brackets are there to build the 2D array needed to write to a range
}
If you want that function to run on edit then just call it onEdit() and you're done !
Source: https://stackoverflow.com/a/64297866/14427194
function onEdit(e) {
//e.source.toast("Entry");
//console.log(JSON.stringify(e));
const sh=e.range.getSheet();
if(sh.getName()=="Sheet1" && e.range.columnStart==20 && e.value=="TRUE") {
const tsh=e.source.getSheetByName('Sheet2');
const nr=tsh.getLastRow()+1;
sh.getRange(e.range.rowStart,1,1,12).moveTo(tsh.getRange(nr,1,1,12));
sh.getRange(e.range.rowStart,16,1,4).moveTo(tsh.getRange(nr,16,1,4));
sh.deleteRow(e.range.rowStart);
}
}