delete entire row if any cell is empty - google-apps-script

Just like the title says. I found a solution if one column is blank, but not if any are blank.
I crafted this with the help of another post, though I don't have a clue re: google scripts.
function onEdit(e) {
//Logger.log(JSON.stringify(e));
//{"source":{},"range":{"rowStart":1,"rowEnd":1,"columnEnd":1,"columnStart":1},"value":"1","user":{"email":"","nickname":""},"authMode":{}}
try {
var ss = e.source; // Just pull the spreadsheet object from the one already being passed to onEdit
var s = ss.getActiveSheet();
// Conditions are by sheet and a single cell in a certain column
if (s.getName() == 'Sheet1' && // change to your own
e.range.columnStart == 1 && e.range.columnEnd == 99 && // only look at edits happening in col C which is 3
e.range.rowStart == e.range.rowEnd ) { // only look at single row edits which will equal a single cell
checkCellValue(e);
}
} catch (error) { Logger.log(error); }
};
function checkCellValue(e) {
if ( !e.value || e.value == 0) { // Delete if value is zero or empty
e.source.getActiveSheet().deleteRow(e.range.rowStart);
}
}
problem is, I have no idea how to actually "use" it

Demo of the setup.
e.range.columnStart and e.range.columnEnd need to be equal to each other in this case

In the spreadsheet that you'd like to use this in, click on Script Editor in the Tools menu. Select Blank Project in the dialog that comes up, and then replace the code in the window with the code you've posted above. Save and name your project, then click Current Project's Triggers in the Resources menu. Click the link to add a new trigger. You'll see a series of drop down boxes, select the function (onEdit()), From Spreadsheet (the event source), and "On Edit" (the event). You have the option to set failure notifications. Click save to save the trigger. You'll be prompted to provide authorization, once you do, the script should run as expected.

Related

Add note based on value of another cell

For all I researched, I know there is not an integrated funcion that can do this, but I know it can be done with scripts. I want a script to create note in one specific cell based on another specific cell value.
example in the sheet I'll share
https://docs.google.com/spreadsheets/d/1I7ictcN_tEQyZXFljAVFm1VqZzafIezF1xR5AYW5pVc/edit?usp=sharing
I want the note on D12 to reflect any changes in the value of A8 for example.
Best case would be, if I could use this script as a function calling whatever cell I wanted.
I saw some examples using onEdit as trigger but I don't know if that would work because the cell in question wouldnt even be touched.
I also saw some exemples using get range to target the cells but then I would have to make a new script for each iteration.
Recording User Edits in A8 in the Notes of D12
function onEdit(e) {
const sh = e.range.getSheet();
if(sh.getName() == "Sheet name" && e.range.columnStart == 1 && e.range.rowStart == 8) {
sh.getRange(12,4).setNote(sh.getRange(12,4).getNote() + '\n' + e.value);
}
}

Google Sheet How to show a Warning or a Modal with input when a cell has data in it?

Basically what i'm trying to say is, this is a spreadsheet for trucks with trailers, if someone inputs a trailer in cell B, can i make it to throw a popup or a Modal or a warning that cell E should have a truck assigned to it, or data and not allow the user to leave cell E empty?. Appreciate the help. how can i do this with a script?
enter image description here
enter image description here
You don't need appscript for that, you can easily do it using data validation.
Select range B:B and open Data Validation dialog box.
Select Custom formula is in criteria.
Use this custom formula =$E1<>"" , select Reject Input. And set custom validation text to show when user violate the above condition.
Try this:
function onEdit(e) {
const sh = e.range.getSheet();
if(sh.getName() == "Your sheet name" && e.range.columnStart == 2 && e.range.rowStart > 1 && e.value) {
if(e.range.offset(0,3).getValue() == '') {
e.range.offset(0,3).setValue("Please Assign Truck Number Here");
e.source.toast('Please Assign Truck',"Truck Assignment",15);
}
}
}
Dont forget to edit the sheet name

How to enable other (non-registered) editors to use the Google Apps Script attached to a Google Sheet?

Hi fellow Stack Overflowers,
Yesterday I used Google Apps Script for the first time and I tried to hide certain rows given on user input. For me this works absolutely fine. Everybody else can access the sheet if they have the link to it and they are allowed to edit certain cells. Another user verified that he can access the Apps Script and as such that it actually is attached to the file, but the Apps Script does not seem to run for anyone else but me.
'
function onEdit(e){
if(SpreadsheetApp.getActiveSheet().getSheetName() == "Cooldown")
{
if (e.range.columnStart != 2 || e.range.rowStart != 5) return;
else if(e.value != "TRUE")
{
SpreadsheetApp.getActiveSheet().hideRows(e.range.rowStart + 1);
SpreadsheetApp.getActiveSheet().getRange('B6').setValue(false);
}
else SpreadsheetApp.getActiveSheet().showRows(e.range.rowStart + 1);
}
else if(SpreadsheetApp.getActiveSheet().getSheetName() == "Benodigde Priesters")
{
if (e.range.columnStart != 2 || e.range.rowStart != 2) return;
else if(e.value != "TRUE")
{
SpreadsheetApp.getActiveSheet().hideRows(e.range.rowStart + 1);
SpreadsheetApp.getActiveSheet().hideRows(e.range.rowStart + 3);
SpreadsheetApp.getActiveSheet().getRange('B3').setValue(false);
SpreadsheetApp.getActiveSheet().getRange('B5').setValue(false);
}
else
{
SpreadsheetApp.getActiveSheet().showRows(e.range.rowStart + 1);
SpreadsheetApp.getActiveSheet().showRows(e.range.rowStart + 3);
}
}
}
As you might have noticed from the Apps Script, its intended purpose is to hide certain rows if a certain checkbox is unchecked and show the rows if it is checked. Rows 3 and 5 are hidden and B3 and B5 are reset to false if B2 is unchecked. Similarly, rows 3 and 5 are shown if B2 is checked.
Picture of the sheet
You are saying that users are "allowed to edit certain cells". That implies that the sheets are protected.
The onEdit(e) function is a simple trigger that runs under the account of the user at the keyboard. If that user does not have the right to edit the columns that you are trying to hide, the function will throw an error when it tries to hide the columns. You can inspect the errors at My Executions.
To make it work, rename the onEdit(e) function to something like hideColumns(e) and use an installable "on edit" trigger to run it. Installable triggers run under the account of the user who set up the trigger.

How can I get the oldValue of a cell, when the user deletes cell content? e.oldValue is undefined in this case

How can I get the oldValue of a cell, when the user deletes the content?
The purpose of this is to prevent accidental deletion / edit when novice users use a shared spreadsheet. Only empty cells should be updated without a warning.
It works when editing the content of the cell.
But when deleting the cell content, oldValue is undefined - the cell had content.
PS. I know this only works for single cell edits - I had a check for range width / height == 1, but that is also not true for a value delete. (select cell, press delete)
My test code below:
function onEdit(e) {
Logger.log("onEdit called")
Logger.log("e.oldValue: %s", e.oldValue)
Logger.log("e.value: %s", e.value)
Logger.log(e)
if (!("value" in e) || (e.oldValue != undefined)) {
if (shouldRevertChange(e.oldValue, e.range.getValue())) {
e.range.setValue(e.oldValue);
}
}
}
function shouldRevertChange(oldValue, newValue) {
var ui = SpreadsheetApp.getUi();
var result = ui.alert(
'Was this a mistake?',
'You changed the contents of a cell. Old value: '+oldValue+', new value: '+newValue+'. Do you want to revert the change?',
ui.ButtonSet.YES_NO);
// Process the user's response.
if (result == ui.Button.YES) {
// User clicked "Yes".
return true;
} else {
// User clicked "No" or X in the title bar.
return false;
}
}
Here is my test sheet - editable:
https://docs.google.com/spreadsheets/d/1BP0Zqbf8QndhI62AucT3nGNm9eUlgzxf0lTCy2UHe-0/edit?usp=sharing
Also test script:
https://script.google.com/d/1IuTpeEDlsqjDyp3ADRy2JYKzDymR7zOpPkamIcEUHnHXUNdA0SRf7xyU/edit?usp=sharing
I need to see in the alert message, the old value from the deleted cell.
Message for editing value:
Logs from editing value:
Message for deleting / clearing value:
Logs for deleting / clearing value (old cell value is nowhere):
There is a plugin that will accomplish this for you. It takes the route of creating a hidden spreadsheet that mirrors the real one.
https://gist.github.com/tanaikech/73edaed1268a6d07118aed538aa5608d
function onEdit(e){
e.range.setNote(e.oldValue);
e.range.setValue(e.range.getNote());
e.range.clearNote();
}
The above function uses the 'Insert note' in cell feature of Google
sheets as a temporary holding variable. A copy of the old value of
the cell is copied as a note, resets the edited value of the cell
and the note is deleted. This code does not specifically check if
the user has hit the 'Delete' key. It replaces any edit made to the
cell with e.oldValue.
To specifically check if the user has hit the 'Delete' key and reset
the cell to e.oldValue the function can be changed to:
function onEdit(e){
if(e.value == null)
e.range.setValue(e.oldValue);
}
Note:
Sheets protected via Apps Script are susceptible to edits made via Google Sheets phone app. In such situations, cell formulae may need to be used. Sheet1 may be used to receive user input. Sheet2 is a mirror of Sheet1 and is locked for editing only by the owner. I use the below formula in cell D5 of Sheet2:
=IF(LEN(Sheet1!D5)=0,"Please enter valid input",Sheet1!D5)
The user needs to check Sheet2 for the output generated based on input given.
Use Below Line to get old value onEdit function
var oldValue = e.oldValue ? e.oldValue : null;

deleteRow based off cell edit on another sheet of same spreadsheet

WHAT I HAVE One google spreadsheet named "Script Test" with two sheets named "delete" and "non delete".
WHAT I NEED If a row in Col B on "non delete" is changed to 'DELETE' via the drop down menu, the row with the same Buy Number on "delete" will be deleted.
WHAT I HAVE TRIED
What has worked = By researching on stack I found an onEdit function that deletes a row on "delete" based on if a cell has a specific value. In this case, that value is 'DELETE'. The problem with this is, I can only get it to work if that cell is on the sheet "delete" rather than the sheet "non delete". If I'm working off of "non delete" and need to go back to "delete" to delete a row of information, I can just right click on the row number and manually delete it. So, this script isn't necessarily saving me time.
This script is as follows:
function onEdit(e) {
try {
var ss = e.source;
var s = ss.getActiveSheet();
if (s.getName() == 'delete' &&
e.range.columnStart == 1 && e.range.columnEnd == 1 && // only look at edits happening in col A which is 1
e.range.rowStart == e.range.rowEnd ) { // only look at single row edits which will equal a single cell
checkCellValue(e);
}
} catch (error) { Logger.log(error); }
};
function checkCellValue(e) {
if (e.value == 'DELETE') {
e.source.getActiveSheet().deleteRow(e.range.rowStart);
}
}
What has not worked = I fiddled with the script a bit to have it read Col F on "delete" and in Col F I have an Index Match of Col B in "non delete". However, this does not delete the row on "delete" when Col F changes to 'DELETE'. Now I'm not 100% on this but I can pretty much deduce that this is happening because Col F isn't being "edited", rather the formula inside of it is "updating". I've also tried fiddling with other scripts that I found on stack but none seem to have gotten me as close as the script above.
THINGS TO THINK ABOUT
First of all, thanks for any help you guys can give me. Just before posting this question, I came across a filter function that I think may be a direction to head in if I'm right about the Index Match. I found one function that hides rows based on a filter but I would need the row to be deleted so I'm assuming that is as simple as switching hideRows with deleteRows. I've tried adding screenshots of what I need done but I don't have enough reputation. I can and will add a link to a copy of the spreadsheet if that helps. Once again, thanks for any tips or guidance.
Copy of Script Test
Use the getSheetByName() method to get the delete sheet.
function checkCellValue(argRowToDelete) {
if (e.value == 'DELETE') {
var toDeltSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("delete");
toDeltSheet.deleteRow(argRowToDelete);
}
}
If you want a separate function just for deleting the row, maybe do the check for the 'DELETE' text in the main function, and pass the row number to the delete function:
I've tested the following code, and it works. When the drop down list is used to select 'DELETE' in the 'non delete' sheet, it deletes the corresponding row in the 'delete' sheet.
I made multiple changes to the code. Even though this code deletes a row in a sheet different from where the edit is taking place, there is still a potential problem. Once a row in the 'delete' sheet is deleted, the rows will shift. If you start deleting rows at the top or middle, then every row below the deleted row is no longer synced with the rows in the 'delete' sheet.
So, this answers your question, but now you have yet another problem.
function onEdit(e) {
try {
var ss = e.source;
var s = ss.getActiveSheet();
var colStart = e.range.columnStart;
var colEnd = e.range.columnEnd;
Logger.log('colStart: ' + colStart);
Logger.log('colEnd: ' + colEnd);
var thisRow = e.range.getRow();
Logger.log('s: ' + s.getName());
//Avoid looking at multi column edits. If column start and column end is same column,
//then not a multi column edit
var editedFromNonDelete = (s.getName() === 'non delete');
Logger.log('editedFromNonDelete: ' + editedFromNonDelete);
var editedFromColB = (colEnd === 2) && (colStart === colEnd);
// only look at edits happening in col B
if (editedFromNonDelete && editedFromColB) {
Logger.log('e.value: ' + e.value);
if (e.value === 'DELETE') {
fncDeleteRow(thisRow);
};
}
} catch (error) {
Logger.log(error);
}
};
function fncDeleteRow(argRowToDelete) {
var toDeltSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("delete");
toDeltSheet.deleteRow(argRowToDelete);
};
After testing out the filter function for a couple minutes, I've pretty much got it to do what I needed. Thanks anyways!