For a Google Sheet, I copied & pasted bits and pieces of scripts I found online to have a warning message show whenever someone edited something in column F. This is working as intended (but maybe a bit slow to 'react').
However, once a month, every value in column F needs to be manually updated by default so in that case, I'd like to have the option to let the users of this sheet skip the warning message or supress the message from being shown.
Is something like that possible? You can find the code below.
function onEdit(e) {//"e" receives the event object
var range = e.range;//The range of cells edited
var columnOfCellEdited = range.getColumn();//Get column number
//Logger.log(columnOfCellEdited)
if (columnOfCellEdited === 6) {
SpreadsheetApp.getUi().alert('You edited the budget column for an account. Sure you dont need to change the account budget in the account?.');
};
};
Using a checkbox to enable monthly update.
You have some onEdit code that warns users that they are making changes to the budget figures in Column F. However once a month there must be extensive editing of the figures in this column, and the the onEdit warning must be turned off.
Say you have a checkbox in cell E1 (with an appropriate label). If you tick the checkbox, it will turn the warning off. If the box is not ticked, then the warning message will be displayed.
The following code would be one way of doing this. The key is the "IF" statement:
if (columnOfCellEdited === 6 && monthlyChk === false) {
This will display the warning only if the edit is in Column F AND if the checkbox is not ticked. You may be concerned about leaving the checkbox in open sight, but you can put/hide the checkbox anywhere you want on the spreadsheet so long as it is appropriately referenced in the code.
function onEdit(e){
//so5920976001
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = e.range;//The range of cells edited
var sheet = range.getSheet();
var columnOfCellEdited = range.getColumn();//Get column number
// checkbox in Cell E1 indicates whether to override for monthly manual adjustments
var monthlyChk = sheet.getRange("E1").getValue();
if (columnOfCellEdited === 6 && monthlyChk === false) {
SpreadsheetApp.getUi().alert('You edited the budget column for an account. Sure you dont need to change the account budget in the account?.');
}
}
Related
I might not be able to explain better, but I will try my best. I have two columns say A and B, in column A there are formulas so values in them get changed depending on some other conditions, Now what I want in column B is to paste/setvalue the value for the first time whenever a value appears in column A, so that when there are any further changes in column A, it wouldn't affect the value that is pasted in column B. Although I have tried my best to write the script, it does paste the value but it pastes in all the column and does not care if any cell in column A is empty.
I have gone through a lot of research but could not find an answer. Although OnEdit can work but as the column from which the value is to be got has formulas in it and OnEdit doesn't work on formulas. So once the script is corrected, we can trigger it to time driven.
I just need the help to make this function work correctly, I will be highly thankful for any help. thank you.
function pastevalue(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sheet1');
var lastrow = ss.getRange("A2:B").getValues().filter(String).length;
var range = ss.getRange(2,1,lastrow);
var pasterange = ss.getRange(2,2,lastrow);
var values = range.getValues().filter(String);
var pastevalues = pasterange.getValues();
for (i=0; i<values.length; i++){
if(pastevalues[i] == ""){
var value = pasterange.setValue(values[i])
}
}
}
I presume that your goal is to grab the numerical value of a formula immediately after you enter it, so that if the displayed value in the cell of the formula changes in the future, you still possess the original value that the formula yielded. The following script accomplishes that:
function onEvent(e){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
if (e.range.getColumn() == 1 && typeof e.oldValue == 'undefined'){
sheet.getRange(e.range.getRow(), 2).setValue(e.range.getValue());
}
}
Note that it is an event trigger, meaning it runs every time the spreadsheet is, well, edited. As the parameter of the function we grab the event that triggered the script (you can read how they are structured here), and then we check for two conditions that both have to be true to copy the value into the B column:
First we check that the column of the cell modified is the A (1st) column.
Then we check that the cell was blank before modification. This will mean that the value will only be copied when a formula is written in a blank cell.
I am building a GAS timestamp function in google spreadsheet which will change the timestamp whenever I revise the cell value in column 10. However, The cell I'd revise now is filled with IFS function, which actually will change itself. The IFS function results to the original timestamp function stop working cause literally the cell value has not changed. Wanna ask if there's any way that I can solve this problem, so that GAS and spreadsheet function could work together smoothly.
function onEdit(e) {
var row = e.range.getRow();
var col = e.range.getColumn();
if(col == 10 && row >1 && e.source.getActiveSheet().getName() === "Sheet 1" ){
e.source.getActiveSheet().getRange(row, 3).setValue(new Date());
}
}
You should review the IFS formula precedent dependencies to find which cells are actually edited by a user then, instead of looking for "edits" on the cells with that formula use the precedent cells.
i.e. Let sayt that you have the following formula in B1.
=A1+1
instead of looking for "edits" on B1 look for edits on A1.
I'm trying to find a way to target emails which have only one label. I want to delete messages which have a specific label and are older than 2 weeks. However, I want the script to ignore any emails which have additional labels besides the specified label.
For example an email with label 'Subscriptions' gets deleted, but an email with label 'Subscriptions' AND 'Keep!' will not.
The version I have currently will delete any email with the specified label regardless of any other labels applied.
I am using the publicly available Gmail Cleaning Robot script by Fred Mouniguet as my base.
Here's what I have so far:
function gmailCleaningRobot() {
var delayDays = 14; // will only impact emails more than 2 weeks old
var maxDate = new Date();
maxDate.setDate(maxDate.getDate()-delayDays); // what was the date at that time?
// Get all the threads labeled 'Subscriptions'
var label = GmailApp.getUserLabelByName("Subscriptions");
var threads = label.getThreads(0, 100);
// we archive all the threads if they're unread AND older than the limit we set in delayDays
for (var i = 0; i < threads.length; i++) {
if (threads[i].getLastMessageDate()<maxDate && threads[i].isUnread())
{
threads[i].moveToTrash();
}
}
}
Any help would be greatly appreciated!
You can solve this by using the getLabels on your thread instance in your if statement.
try the following.
if (threads[i].getLastMessageDate()<maxDate && threads[i].isUnread()
&& threads.getLabels().length == 1)
I have a spreadsheet that takes input of stock symbols. I would like them to always be in ALL CAPS regardless of how they are typed in. This appears to require some scripting as there is no way to do this with a function unless a second copy of the column exists, which is not acceptable.
I have a solution which works, with one critical problem. The code is as follows:
function OnEdit(e) {
var ss = e.source.getActiveSheet(),
sheets = ['Trades', ''],
ind = sheets.indexOf(ss.getName());
if (ind === 0 && e.range.rowStart > 1 && e.range.columnStart >= 1 ) {
e.range.setValue(e.value.toUpperCase());
}
}
It works great, and allows me to add as many tabs and columns to format as I wish. Unfortunately it also capitalizes the FORMULAS inside the cells, which is breaking formulas that use the importhtml() function, because it capitalizes the URL being requested.
So, anyone know a way to do exactly what the above code does, but not touch the actual formulas inside the cells, only the text that they output?
EDIT: Thanks to #ocordova's comment, I thought I had something that would do the job well enough. Unfortunately it's behaving strangely... it works partly o some columns, and not at all on others. Here is my current code (slightly altered from earlier for clarity):
function onEdit(e){
var activeSheet = e.source.getActiveSheet(),
sheets = ['NEW Trades', ''],
sheetIndex = sheets.indexOf(activeSheet.getName());
if (sheetIndex === 0 && e.range.rowStart > 1 && e.range.columnStart >0 && e.range.getFormula() == '') {
e.range.setValue(e.value.toUpperCase());
}
}
Anyone have any ideas why some cells in some columns will capitalize as expected, and other cells in those same columns won't, and yet other columns won't capitalize at all, anywhere?
EDIT 2: My trouble appears to be related to, or a conflict with, Data Validation. The columns I'm trying to capitalize are fed by lists of values on another sheet. If the value was present previously in lower case, and then I applied the data validation to the column, the script will not capitalize the value. However if I select the appropriate, capitalized selection from the data validation list, and then re-type the same value in lower case, the script DOES kick in and capitalize. Very strange and confusing. I could be wrong about the conflict, but that's what it seems like to me.
EDIT 3: It's not related to data validation, because it's behaving the same way on a simple column that has no validation at all. If the value I had previously entered was already in lowercase, then typing it again in lowercase will not activate the script. BUT if I type the value in CAPS, then re-type it in lowercase, the script capitalizes it. Maybe some strange condition relating to when the script is triggered...?
If you don't want to capitalize if the cell contains a formula, you can use the method getFormula() and check if the cell contains a formula.
Returns the formula (A1 notation) for the top-left cell of the range, or an empty string if the cell is empty or doesn't contain a formula.
The code should look like this:
if (ind === 0 && e.range.rowStart > 1 && e.range.columnStart >= 1 && e.range.getFormula() == '') {
e.range.setValue(e.value.toUpperCase());
}
EDIT:
If I've understood you correctly, you're typing exactly the same value, example: if the value in the cell is México, and you delete all or some characters and inmediately type México again, in that scenario the old value and the new value are the same and the OnEdit() won't be fired. Another example is if you change the format of the value, that's another type of event.
If you want know how the event is considered, you can use an installable on change trigger:
function triggerOnChange(e) {
MailApp.sendEmail('john.doe#gmail.com', 'Testing triggerOnChange', JSON.stringify(e));
}
Then in the Script Editor menu: Resources -> Current Project Triggers -> Add a new trigger -> ['triggerOnChange', 'From spreadsheet', 'On change']
On how to change the case of the formula's result, I think #Rubén has the right idea, but it will only work if the formula contains UPPER() in the first characters, and also since you're using the formula IMPORTHTML() using UPPER() will break it and maybe some other functions like array formulas, unless you use INDEX():
=INDEX(UPPER(IMPORTHTML(url, query, index)))
Another option could be Regular expressions, but I think it's a little risky considering all the combinations.
So, anyone know a way to do exactly what the above code does, but not touch the actual formulas inside the cells, only the text that they output?
Consider to make a slight change in the OP approach: rather than capitalize all the cells content for any case, capitalize according the following conditions:
If the cell value, including the values of cells that holds constants or formulas, is not a string then do nothing .
If the cell value is a string
and the cell content is a constant, then change the case directly from the script.
and the cell content is a formula, then nest the original formula inside the built-in function UPPER.
Example:
function onEdit(e) {
var range = e.range;
var value = range.getValue();
var sheet = range.getSheet();
var sheetName = sheet.getName();
if (sheetName === 'Sheet1' &&
range.getRow() > 1 &&
range.getColumn() > 1 &&
typeof value === 'string') {
if(!range.getFormula()) {
range.setValue(value.toUpperCase());
} else {
if(range.getFormula().substring(0,6).toUpperCase() == '=UPPER') {
return;
} else {
range.setFormula('=UPPER(' + range.getFormula().substring(1) + ')');
}
}
}
}
Notes:
For simplicity the ind array was not included.
typeof e.value always returns 'string', so instead range.getValue(); is used.
I am writing a script to bind two cells to always hold the same value after every edit. My script so far looks like this:
function myEdit(event){
var ss = event.source.getActiveSheet();
var r = event.source.getActiveRange();
var bind1 = ss.getRange("D11:D11").getCell(1,1);
var bind2 = ss.getRange("D10:D10").getCell(1,1);
var editedCell = r.getCell(1,1);
Logger.log("checking");
if (editedCell === bind1){
Logger.log("Condition was Met!");
bind1.copyTo(bind2);
}
else if (editedCell === bind2){
Logger.log("Condition was met!");
bind2.copyTo(bind1);
}
else{
Logger.log("No condition was met.");
}
When I change the value in either of the bound cells, nothing is copied anywhere else. When I check the execution logs, it appears everything went fine
[14-07-21 10:47:06:215 EDT] Execution succeeded [0.884 seconds total runtime]
But when I check the Logger logs, I get
[14-07-21 10:55:49:260 EDT] checking
[14-07-21 10:55:49:260 EDT] No condition was met.
For some reason, the program is not recognizing that editedCell and bind1 are the same object, when I edit cell D11.
By checking the values of bind1 and editedCell, the values are the same so they must be referring to the same cell, but the equality operator is not working to check whether they are the same range.
For some reason, the program is not recognizing that editedCell and bind1 are the same object, when I edit cell D11.
The reason that the identity operator === doesn't work in this case is that what is being compared is the Range, not the content of the cells in those ranges. Like Sandy suggests, you need to get the values first, and compare those.
However, comparison isn't needed, is it? Your stated objective is to ensure D10 and D11 contain the same value after every edit. Since the only edit that can affect either is a change to themselves, you can ignore any edit made to any cells but D10 or D11. Further, if either of them changes, and myEdit() is invoked, you know they are different, so you can just copy the newly changed value to the other cell.
Something like this:
function myEdit(event){
// To check whether we need to do anything, find which cell was edited.
// Get the A1 notation for the changed cell.
var cellA1 = event.range.getA1Notation();
if (cellA1 == "D10") {
// D10 changed, so copy value to D11
event.range.offset(1,0).setValue(event.value);
}
else if (CellA1 == "D11") {
// D11 changed, so copy value to D10
event.range.offset(-1,0).setValue(event.value);
}
// Any other cell, do nothing.
}