Google Apps Script - How to get clipboard column number - google-apps-script

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!

Related

Automatically populate cell in Google Sheets when another cell in same row is manually filled but error

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 import from other googlesheet file and using query to import the data. I currently using script but i cant put a apostrof to complete my formula
`
function onEdit(e) { //Runs every time the sheet is edited
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('DB Mitra'); //Change this to whatever your sheet is named
var inputCol = sheet.getRange('B2'); //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('D'+row); //Change to the column that will store the generated code value
codeCell.setValue('=QUERY({IMPORTRANGE("1-K_ZltvOev2t9iqKIOHR8B-PY6ODBKYAwTjaDzLbHJE";"2022!B2:T494")};"SELECT Col4 WHERE Col1 = '"&B'+row+'&"'")');
//let hardValue = codeCell.getValue(); //Gets the value from the formula you just entered
//codeCell.setValue(hardValue); //Replaces the formula with just the resulting value
};
}
`
the formula should be like this
enter image description here
but it always error if i put it like that
enter image description here
Thank you for anyone willing to help me. credit to Automatically populate cell in Google Sheets when another cell in same row is manually filled for the inspiration code
In your script, how about modifying using the template literals as follows?
From:
codeCell.setValue('=QUERY({IMPORTRANGE("1-K_ZltvOev2t9iqKIOHR8B-PY6ODBKYAwTjaDzLbHJE";"2022!B2:T494")};"SELECT Col4 WHERE Col1 = '"&B'+row+'&"'")');
To:
codeCell.setValue(`=QUERY({IMPORTRANGE("1-K_ZltvOev2t9iqKIOHR8B-PY6ODBKYAwTjaDzLbHJE";"2022!B2:T494")};"SELECT Col4 WHERE Col1 = '"&B${row}&"'")`);
or
codeCell.setFormula(`=QUERY({IMPORTRANGE("1-K_ZltvOev2t9iqKIOHR8B-PY6ODBKYAwTjaDzLbHJE";"2022!B2:T494")};"SELECT Col4 WHERE Col1 = '"&B${row}&"'")`);
Reference:
Template literals

Google Sheet Copy Column Data On Edit

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

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.

Running a formula in the background of a cell on Sheets

I am trying to make a sheet where I can type a time (duration) into a cell without colons or decimals and it show up in the same cell with the colons and decimals (example: input "10342" and the cell reads "1:03.42"). The formula I have that works in another cell is:
=ARRAYFORMULA(TEXT(AVERAGE(VALUE(IF(D3<>"", TEXT(
IF(IFERROR( LEFT(D3, LEN(D3)-6))="", 0, LEFT(D3, LEN(D3)-6))&":"&
IF(IFERROR(RIGHT(LEFT(D3, LEN(D3)-4), 2))="", "00", RIGHT(LEFT(D3, LEN(D3)-4), 2))&":"&
IF(IFERROR(RIGHT(LEFT(D3, LEN(D3)-2), 2))="", "00", RIGHT(LEFT(D3, LEN(D3)-2), 2))&"."&
IF(LEN(D3)>1, RIGHT(D3, 2), "0"&D3), "[h]:mm:ss.00"), ))), "[h]:mm:ss.00"))
I have tried conditional formatting and I'm not the greatest with macros. Is there anyway that this would be possible?
You clearly need an onEdit function. You have to open the script editor within your spreadsheet file and copy paste the code snippet I provide here. With the following code, every time you edit a cell in column A of "Sheet1" you get back the desired format of your input to the exact same cell. If the value you enter is: 10342 it will become: 1:03.42 . If the value you enter is 130342 you get back 13:03.42 . If you want to edit cells only after row 1 (in case you have a header) you can add in the if condition statement the condition : row >1.
function onEdit(e) {
var row = e.range.getRow();
var col = e.range.getColumn();
if (col === 1 && e.source.getActiveSheet().getName() === "Sheet1"){
var valu = e.source.getActiveSheet().getRange(row,1).getValue().toString()
if (valu.length == 5){
var result = valu.slice(0,1)+":"+valu.slice(1,3)+"."+valu.slice(-2);
}
else if ( valu.length==6) {
var result = valu.slice(0,2)+":"+valu.slice(2,4)+"."+valu.slice(-2);
}
e.source.getActiveSheet().getRange(row,1).setValue(result);
}
}
Don't forget to modify the name of the sheet (in my case "Sheet1") as well as the column you want to work with. As you can see my solution uses col===1, e.source.getActiveSheet().getRange(row,1).setValue(result) and var valu = e.source.getActiveSheet().getRange(row,1).getValue().toString(). Number 1 corresponds to column A. If you want to work with column D, for example, you need to replace 1 with 4 for all these formulas. Let me know in the comments if you have any questions.

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]] )