Clear columns of selected cell row? - google-apps-script

I want to clear contents of selected row (not delete entire row). Can someone help?
Eg: D3 is selected
Clear D3,E3,F3,G3,H3 but not delete the row

Explanation:
You are looking for the onSelectionChange(e).
The following script will clear D:H of the row/cell you selected in column D.
Code snippet:
function onSelectionChange(e) {
const sheetName = "Sheet1"; // put the name of your sheet here
const range = e.range;
const sheet = range.getSheet();
if(sheet.getName()==sheetName && range.getColumn() == 4){
sheet.getRange(range.getRow(),4,1,5).clearContent();
}
}
I hope it is clear that this is a trigger function. Namely, you are not supposed to manually execute it by yourself but it will be triggered upon selections in the sheet (see Illustration).
Illustration:
Possible Restriction:
onSelectionChange is a little bit buggy but it can work really well. If it does not work in the beginning, disable the v8 run time environment, refresh the script editor page and then enable v8 environment again. You might need to wait or refresh the page again but it will eventually work. Please read the related issue here.

Simply select the cells the you wish to clear and hit backspace to clear the contents of the cells.
Alternatively, run this function in the script editor:
function clearData(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('THE_NAME_OF_YOUR_SHEET').getRange('D3:H3');
ss.clear();
}

function Deleterow() {
const sheetName = "Anju"; // put the name of your sheet here
var range = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getActiveCell();
const sheet = range.getSheet();
if(sheet.getName()==sheetName && range.getColumn() == 4){
sheet.getRange(range.getRow(),4,1,5).clearContent();
}
}

Related

How do you delete/move a row based on the value of a cell changing?

I have a "Task" tab that has a priority and status for each task. I want to delete the task from "Tasks" and add a row to "Completed Tasks" when the status of that task changes to completed. I've been playing around with Macro and the on edit feature. But it's a little complicated for me because both my tables of data are on different rows and columns. So it's not lining up very well. I'll post my spreadsheet to help give you guys a better idea of what I'm talking about.
Google Spreadsheet: https://docs.google.com/spreadsheets/d/1rnICvztZiKXXeXX6ZZhmeJ99BS0yS_K4HAEAuLHEbyA/edit?usp=sharing
I've tried using Macro and using a for loop of sorts. But it's just a big mess now
You were on the right track. Just a few things to note:
You are correct that you need to use onEdit, but it needs to be an Installable Trigger. You can install the trigger manually - just follow the instructions.
You need to make use of Event Objects. This gives you access to the name of the edited sheet, the edited value, and the edited row.
function clearRow(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
// define the edit Sheet Name for use in the IF
var editSheetName = "Tasks"
var editSheet = ss.getSheetByName("Tasks");
// get the eddited value for use in the IF
var eVal = e.value
// test for the "Tasks" sheet and for the tick mark
if(ss.getActiveSheet().getSheetName() === editSheetName && eVal === '✅'){
// define the target sheet
var targetSheet = ss.getSheetByName("Completed Tasks")
// get the editted row
var eRowStart = e.range.rowStart
// get the last row in the target sheet
var targetLR = targetSheet.getLastRow()
// define the range in the edit sheet and 'Get' the values
var editValues = editSheet.getRange(eRowStart,1,1,5).getValues()
// define the range in the target sheet and 'set the Values
targetSheet.getRange(targetLR,1,1,5).setValues(editValues)
// delete the edited row in the edit sheet
editSheet.deleteRow(eRowStart)
}
else{
// Logger.log("DEBUG: no match")
}
}

Why can't my shared users use my script I have written into the Google Sheet?

I have made a Google Sheet for job tracking. I wrote a script to hide certain rows once a field is entered into a specific cell.
This is the script:
function myFunction() {
}
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName("PRODUCTION TRACKER"); // Enter sheet name
var row = s.getRange('AK:AK').getValues(); // Enter column letter that has
//the text "hide" and "unhide"
s.showRows(1, s.getMaxRows());
for(var i=0; i< row.length; i++){ if(row[i] == 'YES') { s.hideRows(i+1, 1); } //Value to hide
}}
It's very simple and works just fine for me. But why does it not work for my Shared users? This script is something that is done automatically once a cell has a certain value, it's not a button or anything.
Explanation:
It seems that your code does not match the description you have given at the last comment. Basically, this is what your code does:
For every cell edit, it shows all the rows, even if they were previously hidden, then the script rechecks each row in column AK for the value 'YES', and hides those rows one by one.
Given your use case, the script could execute a lot of sheet changes, i.e. hideRows(i+1,1) for each cell edit. Sheet changes are very slow and greatly impact execution time.
You might have reached the quota of 90 min / day for triggers. Maybe not in your account, but in your shared users'.
Solution:
Unless there's a need for this specific behavior, you can optimize the code by utilizing the event object in the function:
function onEdit(e) {
var s = e.range.getSheet();
if (s.getName() == "PRODUCTION TRACKER" &&
e.range.getColumn() == 37 &&
e.value == "YES") {
s.hideRows(e.range.getRow());
}
}
Note that you can still use the original code, but not inside a trigger.

Google Sheets change tab name based on cell value of a DIFFERENT tab

Ok so I currently am running this script which works perfect if you make an edit on the current tab you're wanting to change the sheet name for...
function onEdit(e) {
if(e.range.getA1Notation() !== 'A1') return;
var s = e.source.getActiveSheet()
s.setName(s.getRange('A1')
.getValue())
}
What I tried to do is use a query formula that will change the cell value based on the cell of a different tab. That didn't work, because it's not them making an edit. It's happening automatically when the cell in a different tab changes. Is there any script that would allow me to change the tab name based on the value of a cell from a different tab?
Maybe I need to be using OnChange instead? Does anyone have an example to make OnChange do the same thing?
You should assign the page you'd like to rename as a variable as follows
const sheet2 = ss.getSheets()[1]
and call it.
Here is a simple example code:
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet1 = ss.getSheetByName('Sheet1')
const sheet2 = ss.getSheets()[1]
function onEdit(e) {
if (e.range.getSheet().getSheetId() == sheet1.getSheetId()
&& e.range.getA1Notation() == 'A1') sheet2.setName(e.value)
}
And here is a working example sheet.

onSelectionChange for a specific Google Sheets tab

Here is my test sheet.
Goal: whenever I click on cells A5:A10 in 'Sheet 1', I want the value of A1 to change to B5:B10.
For example: if I click A7, A1 = B7.
Note: I don't want this script to run for any other sheet or document.
Can you please help me create a script to run automatically for this purpose?
Explanation:
Indeed, the onSelectionChange(e) trigger is what you are looking for.
You just need to take advantage of the event object to capture information of the selected cell.
When you click on a particular cell in range A5:A10 of Sheet1 the following script will update the value of cell A1 to the corresponding value of B5:B10.
What is important here is to understand the if condition I used:
if (as.getName() == 'Sheet1' && row>4 && row<11 && col==1)
Essentially, I am asking for selections only in Sheet1, after row 4 and before row 11 and column 1. That is basically the range A5:A10.
Solution:
function onSelectionChange(e) {
const as = e.source.getActiveSheet();
const row = e.range.getRow();
const col = e.range.getColumn();
if (as.getName() == 'Sheet1' && row>4 && row<11 && col==1){
as.getRange('A1').setValue(as.getRange(row,2).getValue());
}
}
You could also use offset to get the value of the next column instead of hardcopying the number 2.
Replace:
as.getRange('A1').setValue(as.getRange(row,2).getValue());
with:
as.getRange('A1').setValue(e.range.offset(0,1).getValue());
but both approaches work just as fine.
As an alternative to what Marios suggests, I prefer exiting as early as possible (since the onSelectionChange can fire very rapidly, I find it somewhat more performant). So, you can move your check to the top of the function (the rest still apply):
function onSelectionChange({ range }) {
const sh = range.getSheet();
const shname = sh.getSheetName();
if( shname !== "<sheet name here>" ) { return; }
//continue if ok
}
Note that usually, it is better to put the sheet name in a configuration object (or, even better, in a function that returns a configuration object) for easy maintenance.
Also, since each sheet has a unique Id (you can visually find it in the gid anchor of the open spreadsheet URL or programmatically with the method mentioned below), you could save you some trouble if the sheet gets renamed and check for id match instead with getSheetId:
function onSelectionChange({ range }) {
const sh = range.getSheet();
const id = sh.getSheetId();
if( id !== 123456789 ) { return; }
//continue if ok
}

How do I deselect an active cell when clicking on an image to run a script?

I have a spreadsheet-bound script that is invoked by clicking an image in the spreadsheet. I've found that the script can be blocked if a cell that it needs to modify is active or being edited by the user.
The code could be anything, even as something as simple as this:
function newf() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange("R4");
range.clear();
}
When the cell R4 is open, the function will ignore the cell.
How do I deselect an open cell when clicking on an image to run a script?
The easy (manual) solution would be to click off the open cell prior to clicking on the image, but I am trying to make the script fool-proof and this can be a costly concern. Is there any way that the function can forcefully deselect an active cell?
Edit: I do not mean active cell. Definitely "open cell." Here are pictures of the error.
Open cell with data being entered
Clicked on Picture, program ran
You can use Sheet.setActive() to move the attached user's cursor to a different location in the spreadsheet. You need to remember that there is a relationship between the User Interface and scripts invoked from it, which is what allows the script to determine and change the currently active cell. This does not extend to the multiple user case, though - if User1 is editing the guarded cell when User2 clicks to run the script, the script will have no idea about it.
function newf() {
var safePlace = "A1"; // Some safe cell
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var activeCell = ss.getActiveCell();
if (activeCell.getSheet() == sheet && activeCell.getA1Notation() == "R4")
sheet.setActiveSelection(safePlace);
var range = sheet.getRange("R4");
var activeCell = ss.getActiveCell();
if (activeCell.getA1Notation() == range.getA1Notation() && activeCell.getSheet().getName() == range.getSheet().getName()) {
// Move user from target cell
sheet.setActiveSelection(safePlace);
range.clear();
}
I had the same problems, both the initial one and with the solution proposed by Mogsdad.
I resolved it the following way:
Before running any of the script, the first three lines get a different sheet opened and the spreadsheet gets flushed:
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('DIFFERENT SHEET NAME'), true);
SpreadsheetApp.flush();
The rest of the script follows.
Then at the end of the script, I reopen the initial sheet with a simple:
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('ORIGINAL SHEET NAME'), true);
Another "solution" to this is not to use a button, but use a check mark as if it we a button, and use the onEdit function.
function onEdit(e)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
checkbox1 = ss.getRange("saveCheckbox_001");
if (checkbox1.isChecked())
{
submit1(); //do all the fun stuff associated with this checkbox
checkbox1.uncheck();
}
//more checkbox handling and calling other functions can go here if you need more than one "button"
}