I have some script that allows me to select multiple items from a drop down in google sheets. I have the below script which works fine for column L(12) but I want this to also work on column M(13) and N(14). I have tried || (as in OR) which then makes all the drop downs in the sheet also allow multiple selections which I don't want. Can anyone help me with this?
function onEdit(e) {
var oldValue;
var newValue;
var ss=SpreadsheetApp.getActiveSpreadsheet();
var activeCell = ss.getActiveCell();if(activeCell.getColumn() == 12 && ss.getActiveSheet().getName()=="Client information"){
newValue=e.value;
oldValue=e.oldValue;
if(!e.value) {
activeCell.setValue("");
}
else {
if (!e.oldValue) {
activeCell.setValue(newValue);
}
else {
if(oldValue.indexOf(newValue) <0) {
activeCell.setValue(oldValue+','+newValue);
}
else {
activeCell.setValue(oldValue);
}
}
}
}
}
function myFunction() {
}
You need to make sure that those columns should be within the range of the statement as what dared provided as an answer. column should be within 12 and 14 inclusively.
Additionally, I have made some modifications to make use of the event object instead of SpreadsheetApp and improved your if-else block.
Code Modifications:
function onEdit(e) {
// Spreadsheet object can be retrieved from event via e.source
var sheetName = e.source.getActiveSheet().getName();
// Range object can be retrieved from event via e.range
var range = e.range;
var column = range.getColumn();
if (sheetName == "Client information" && column >= 12 && column <= 14 && e.value) {
var newValue = e.value;
var oldValue = e.oldValue;
// first if statement is the default behavior, no need to include
// the else statement is now combined on the outer if statement
if (!e.oldValue)
range.setValue(newValue);
else {
if (oldValue.indexOf(newValue) < 0)
range.setValue(oldValue + ',' + newValue);
else
range.setValue(oldValue);
}
}
}
Output:
function onEdit(e) {
// cache the column number
let col = e.range.getColumn()
if ( e.source.getActiveSheet().getName() === "Client information" &&
col > 11 && col < 15) {
// This block will run if any of the columns L, M or N are edited
// If you need different behaviour depending on which column was edited test the column number
// Column L
if (col === 11) {
// This block will run if column L is edited
}
}
// Without seeing the type of data you are working with I'm unclear on what
// your old and new values represent.
}
Related
Evening everyone!
I asked this about a week back, but I think the thread got lost in the ether. We came close, but I'm trying to create a function where "Transfer a range of Rows from sheet 1 to sheet 2. Sheet 1 has order IDs in column E. G will have =unique to show me all current order IDs, with check boxes next to each unique reference. Check the box next to which ones you want to CUT over > Select a menu run add on > Run Script > all Rows from A:E that match the desired ID are moved".
[Picture Reference]
Sheet Reference
function onEdit(e) {
e.source.toast('Entry')
const sh = e.range.getSheet();
if(sh.getName() == "Reference" && e.range.columnStart == 8 && e.range.rowStart > 1 && e.value == "TRUE") {
e.source.toast('Gate1')
let rg = sh.getRange(e.range.rowStart,1,1,5)
let vs = rg.getValues();
const osh = e.source.getSheetByName("Processing");
osh.getRange(osh.getLastRow() + 1,1,1,5).setValues(vs);
rg.deleteCells(SpreadsheetApp.Dimension.ROWS);
e.range.setValue("FALSE");
}
}
Here is what we had so far. Please let me know if anyone can help, thank you!
To get all rows that match the unique ID whose checkbox was ticked, use Array.filter(), like this:
/**
* Simple trigger that runs each time the user hand edits the spreadsheet.
*
* #param {Object} e The onEdit() event object.
*/
function onEdit(e) {
if (!e) {
throw new Error(
'Please do not run the onEdit(e) function in the script editor window. '
+ 'It runs automatically when you hand edit the spreadsheet.'
+ 'See https://stackoverflow.com/a/63851123/13045193.'
);
}
moveRowsByUniqueId_(e);
}
/**
* Triggers on a checkbox click and moves rows that match a unique ID.
*
* #param {Object} e The onEdit() event object.
*/
function moveRowsByUniqueId_(e) {
let sheet;
if (e.value !== 'TRUE'
|| e.range.rowStart <= 1
|| e.range.columnStart !== 8
|| (sheet = e.range.getSheet()).getName() !== 'Reference') {
return;
}
e.source.toast('Moving rows...');
const uniqueId = e.range.offset(0, -1).getValue();
const range = sheet.getRange('A2:E');
const values = range.getValues();
const targetSheet = e.source.getSheetByName('Processing');
const _matchWithId = (row) => row[4] === uniqueId;
const valuesToAppend = values.filter(_matchWithId);
if (uniqueId && valuesToAppend.length) {
appendRows_(targetSheet, valuesToAppend);
range.clearContent();
const remainingValues = values.filter((row) => !_matchWithId(row));
range.offset(0, 0, remainingValues.length, remainingValues[0].length)
.setValues(remainingValues);
e.source.toast(`Done. Moved ${valuesToAppend.length} rows.`);
} else {
e.source.toast('Done. Found no rows to move.');
}
e.range.setValue(false);
}
For that to work, you will need to paste the appendRows_() and getLastRow_() utility functions in your script project.
It work almost like asked but :
it's using a personal lib (available below)
didn't make the part realtiv of removing range and aggregate result, I hope i can add it to the lib some day. However, empty cell are fill with -
for an obscure reason, it doesn't like the TRUE/FALSE cell, but work like a charm with 1/0 or any other texte value, regex, ...
Additional error handling are to be added if not any match or others possibilites
function onEdit(e){
console.log(SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Reference").getRange("H3").getValue())
var tableReference = new TableWithHeaderHelper(SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Reference").getRange("A1").getDataRegion());
var tableReferenceId = new TableWithHeaderHelper(SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Reference").getRange("G11").getDataRegion());
var tableProcessing = new TableWithHeaderHelper(SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Processing").getRange("A1").getDataRegion());
// get value
var id = tableReferenceId.getTableWhereColumn("Move to Sheet").matchValue(1).getWithinColumn("Unique Filter").cellAtRow(0).getValue();
var tableWithinId = tableReference.getTableWhereColumn("Shipment ID").matchValue(id)
for(var i=0 ; i < tableWithinId.length() ; i++){
var rangeRowWithinId = tableWithinId.getRow(i);
tableProcessing.addNewEntry(rangeRowWithinId);
for(var cell in rangeRowWithinId.getRange()) cell.setValue("-");
}
//reset value
tableReferenceId.getTableWhereColumn("Move to Sheet").matchValue(1).getWithinColumn("Move to Sheet").cellAtRow(0).setValue(0)
}
See below the app script file you need to create in order to use this utils function:
https://github.com/SolannP/UtilsAppSsript/blob/main/UtilsGSheetTableHelper.gs
I'm trying to get a counter going in google sheets that will count how many times a cell has changed or updated.
I want cell "K1" to count how many times cell "Client!A2" values have changed.
This is my first time using Apps-Script so I feel like I must be missing something here. This is what has been input into the code.gs section.
function onEdit(e) {
if(e.range.getA2Notation() == "Client!A2") {
var sCounter = e.source.getRange("K1");
var counter = sCounter.getValue();
if(counter === 0) {
counter = 1;
} else {
counter ++;
}
sCounter.setValue(counter);
}
}
It doesn't seem to be working,
Am I supposed to be putting anything else in the brackets? Or am I just doing it wrong altogether?
function onEdit(e) {
const sh = e.range.getSheet();
const shts = ['Sheet1','Sheet2'];//included sheets
const idx = shts.indexOf(sh.getName());
if(~idx && e.value != e.oldValue) {
let n = Number( PropertiesService.getScriptProperties().getProperty('editcounter'));//counter
PropertiesService.getScriptProperties().setProperty('editcounter',++n);
sh.getRange('K1').setValue(n);
e.source.toast(n);
}
}
I have a planner type Google spreadsheet where data added daily by 8-10 users. When I add a date to a cell, I want all the cells in the same row after that date to be formatted and added a text value something like "ENDED".
At the moment I am doing it with conditional formatting and with an ArrayFormula to add the text value. The problem is that for the ArrayFormula to work the cells must be empty and in my sheet the cells they might contain data before the "ENDED" date cell.
Is there a way to do this with a script?.... and if the script can handle also the formatting of the cells that will be the best solution.
Here is my sample file to understand better what I am trying to do...
https://docs.google.com/spreadsheets/d/1QplyEcNu-svYwFq9wvPVEKnsEP1AnrlAkbBxNwEFPXg/edit#gid=2087617521
You can do this with a trigger and a custom function.
Create a new apps script project and use this code:
function onEdit(e) {
if (e.range.getColumn() ==2) {
//User edited the date column
if (typeof e.range.getValue() === typeof new Date()) {
//Value of edit was a date
endColumns(e.range.getRow(), e.range.getValue());
} else if (e.range.getValue() === "" || e.range.getValue() === null) {
var sheets = SpreadsheetApp.getActiveSheet();
var resetRange = sheets.getRange(e.range.getRow(), e.range.getColumn()+1, 1, sheets.getMaxColumns()-e.range.getColumn());
resetRange.clear(); //Will delete all text, not only the "ENDED" text.
}
}
}
function endColumns(rowNum, limitDate) {
var sheets = SpreadsheetApp.getActiveSheet();
var colOffset = 3; //Offset to account for your row Headers
var dateHeader = sheets.getRange(1, colOffset, 1, sheets.getMaxColumns()-colOffset);
var availableDates = dateHeader.getValues()[0];
var foundCol = 0;
for (var i=0; i<availableDates.length; i++) {
if (availableDates[i]>=limitDate) {
break;
}
foundCol++;
}
var rewriteCells = sheets.getRange(rowNum, foundCol+colOffset, 1, sheets.getMaxColumns()-(foundCol+colOffset));
//Add your formatting and text below:
rewriteCells.setValue("Ended");
rewriteCells.setBackground("red");
rewriteCells.setFontColor("yellow");
//Clear all cells that are "white" (no header)
for (var i=0; i<availableDates.length; i++) {
if (availableDates[i]==="" || availableDates[i] ===null) {
sheets.getRange(rowNum, colOffset+i).clear();
}
}
}
Then, create a trigger to run the onEdit function on every edit.
In this case there are some hardcoded values:
e.range.getColumn() == 2 for the row where you add the dates on
var colOffset = 3 for the number of columns to skip before reading the dates
Hope this helps!
I'm working on a script that is giving me trouble. Column G has picklist values M1, M2,M3,S1,S2,S3,S4,S5,C1,C2,C3. I would like to have a timestamp inserted in column t when any of the S-values (S1,S2,S3,S4,S5) are selected from the picklist. I would like this done on the first occurrence only, not when the picklist value in column g is subsequently updated or changed.
I'm close, but the current script updates the date in the entire column t.
I'd also like to clean up line 9 if possible.
I have this so far:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('ClientList');
var stageValues = s.getRange('g3:g').getValues();
var dateValues = s.getRange('t3:t').getValues();
for (var row in stageValues)
for (var col in stageValues[row])
if (stageValues[row][col] == 'S1' || stageValues[row][col] == 'S2' || stageValues[row][col] == 'S3' || stageValues[row][col] == 'S4' || stageValues[row][col] == 'S5' && dateValues[row][col] == '') {
num = parseInt(row) + 3;
s.getRange('t' + num).setValue(new Date());
}
};
You say picklist values, i'm assuming you mean a dropdown list. But regardless this will work. When ever a cell is manually edited in column G the onEdit trigger will check for an "S" value and the time stamp in column T. If no time stamp is found it will place a new time stamp. "e" is the trigger object containing information about the cell that was edited.
function onEdit(e) {
try {
if( e.range.getSheet().getName() === "ClientList" ) {
if( e.range.getColumn() === 7 ) { // edit in column G
if( e.value.charAt(0) === "S" ) {
if( e.range.offset(0,13,1,1).getValue() === "" ) { // no value in T
e.range.offset(0,13,1,1).setValue(new Date());
}
}
}
}
}
catch(err) {
Logger.log(err);
}
}
I have put together a google spreadsheet that highlights the first four cells in a row if the value in cell 6 is within 3 days of the current date, but I cannot figure out how to add an if/and statement to exclude all entries that have "East" in row E.
This is the code that I have had success with, minus the exclusion of East not highlighting.
onEdit(e) {
if (e) {
var ss = e.source.getActiveSheet();
var r = e.source.getActiveRange();
if (r.getRow() != 2 && ss.getName() == "Sheet1") {
Days_Remaining = ss.getRange(r.getRow(),6).getValue();
rowRange = ss.getRange(r.getRow(),1,1,4);
if (Days_Remaining < 3.8) {
rowRange.setBackgroundColor("#FF0000");
} else if (Days_Remaining == 'N/A') {
rowRange.setBackgroundColor("#ffffff");
} else if (Days_Remaining > 3.9) {
rowRange.setBackgroundColor("#ffffff");
https://docs.google.com/spreadsheet/ccc?key=0AqtCuK7ex8ZNdGxKLUZpQnZ3UzRCV3VoclVDbFVqQnc#gid=0
If you use the new Google Sheets, you can simplify by using Conditional Formatting
If not, you need to get the values in column 5 as well and add an IF block based on that. For example:
Follow_up = ss.getRange(r.getRow(),5).getValue();
And then, before you check Days_Remaining, you should add
If(Follow_up <> "East") {//rest of the checks here }