Multiple Columns for First Level Dependent Dropdown List - google-apps-script

I have a spreadsheet with 4 columns that i am concerned with:
Group (Ferrous/Non-ferrous/etc.)
RI No. (Unique identifier)
Item Description (Name of the chosen RI No. item)
Supplier (Sellers of chosen RI No.)
The flow of data happens like this:
I select Group (say, Ferrous) --> In RI No. column, an automatic dropdown is created, showing RI Nos. of all items under Ferrous category show up --> I select a particular RI No. from this drop-down --> Item Description appears through VLOOKUP --> A drop-down of all sellers selling that item show up in in Supplier column.
Now, I wrote a code which does this work perfectly, but i was wondering if there was a way to make it so that:
I select Group (say, Ferrous) --> In RI No. column AND in Item Description column, an automatic dropdown is created, showing RI Nos. of all items under Ferrous category show up --> If I select RI No., item description gets populated/If I select Item Description, RI No. gets populated --> corresponding suppliers list show up as they do now.
Sample spreadsheet: https://docs.google.com/spreadsheets/d/16qv-OgCIezEuaOm8fQdq91FiQbBny4MzGRIho9ZCY-E/edit#gid=1605627126
The code:
var ws = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var wsopt = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sorted items");
var opts = wsopt.getRange(2,1,wsopt.getLastRow()-1,13).getValues();
var firstlevelcolumn = 2;
var secondlevelcolumn = 5;
var thirdlevelcolumn= 6;
var wsopt2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("supplier details");
var opts2 = wsopt2.getRange(3,1,wsopt2.getLastRow()-1,12).getValues();
function onEdit(e)
{ var activecell= e.range;
var val = activecell.getValue();
var r= activecell.getRow();
var c= activecell.getColumn();
var wsName= activecell.getSheet().getName();
if (wsName == "JPS")
{
if (wsName == "JPS" && c == firstlevelcolumn && r > 2)
{ applyFirstLevelValidation(val,r);}
if (wsName == "JPS" && c == secondlevelcolumn && r > 2)
{ applySecondLevelValidation(val,r);}
}//JPS
else if (wsName == "DDNI")
{
if (wsName == "DDNI" && c == firstlevelcolumn && r > 2)
{applyFirstLevelValidation(val,r);}
if (wsName == "DDNI" && c == secondlevelcolumn && r > 2)
{ applySecondLevelValidation(val,r);}
}//DDNI
}//close onEdiT
function applyFirstLevelValidation(val,r)
{
if(val=== "")
{
ws.getRange(r,secondlevelcolumn).clearContent();
ws.getRange(r,secondlevelcolumn).clearDataValidations();
ws.getRange(r,thirdlevelcolumn).clearContent();
ws.getRange(r,thirdlevelcolumn).clearDataValidations();
} else
{
ws.getRange(r,secondlevelcolumn).clearContent();
ws.getRange(r,secondlevelcolumn).clearDataValidations();
ws.getRange(r,thirdlevelcolumn).clearContent();
ws.getRange(r,thirdlevelcolumn).clearDataValidations();
var filteredopts = opts.filter(function(o){return o[0]===val});
var listToApply = filteredopts.map(function(o){return o[1]});
var cell=ws.getRange(r,secondlevelcolumn);
applyValidationToCell(listToApply,cell);
}//close else
}//close applyFirstLevelValidation
function applySecondLevelValidation(val,r)
{
if(val=== "")
{
ws.getRange(r,thirdlevelcolumn).clearContent();
ws.getRange(r,thirdlevelcolumn).clearDataValidations();
} else
{
ws.getRange(r,thirdlevelcolumn).clearContent();
ws.getRange(r,thirdlevelcolumn).clearDataValidations();
var firstlevelcolvalue = ws.getRange(r,firstlevelcolumn).getValue();
var filteredopts2 = opts2.filter(function(o){return o[6]===firstlevelcolvalue && o[4]===val});
var listToApply2 = filteredopts2.map(function(o){return o[0]});
var cell2=ws.getRange(r,thirdlevelcolumn);
applyValidationToCell(listToApply2,cell2);
}//close else
}
function applyValidationToCell(list,cell)
{
var rule = SpreadsheetApp.newDataValidation().requireValueInList(list).build();
cell.setDataValidation(rule);
}

Related

Set cell value using if statement

I'm trying to use an if statement in scripts to set cell values once conditions are met, however its not working and i can't figure out why.
I need to do it using scripts rather than formulas in the sheet itself
var mainWSname = "Exposure"
function onEdit(e){
var activeCell = e.range();
var r = activeCell.getRow()
var c = activeCell.getColumn()
var val = activeCell.getValue();
var wsName = activeCell.getSheet().getName()
if(wsName === mainWSname && c === 2 && val === "Match"){
wsName.getRange(r, 3).setValue("18")
wsName.getRange(r, 4).setValue("80")
}
}
Try this modification:-
var mainWSname = "Exposure"
function onEdit(e){
var activeCell = e.range;
var r = activeCell.getRow()
var c = activeCell.getColumn()
var val = e.value;
var wsName = activeCell.getSheet()
if(wsName.getName() === mainWSname && c === 2 && val === "Match"){
wsName.getRange(r, 3).setValue("18")
wsName.getRange(r, 4).setValue("80")
}
}
Reference:
Event Object

How can I create a filter area in Google Sheets using Google Apps Script?

enter image description here
I want to create a filter area in A1 and A2 cells so that when I put drivers' name on these cells, the table (A:C) should be filtered according to the value entered in A1 and A2. Can someone explain me how to write Apps Script to perform such function?
Thank you in advance!
Try, with both names in C1 and C2 (pls, change sheet name as necessary)
function onEdit(e) {
var col = 3
var sh = e.source.getActiveSheet()
if (sh.getName() != "Sheet1") return;
if (e.range.columnStart > col || e.range.columnEnd < col) return;
if (e.range.rowStart > 2) return;
var names = sh.getRange(1, col, 2, 1).getValues().flat()
var range = sh.getRange(3, col, sh.getLastRow() - 2, sh.getLastColumn() - col + 1);
var filter = sh.getFilter();
if (filter !== null) filter.remove();
if (countNotOccurrences(names, '') == 0) return;
var hiddenNames = range.getValues().slice(1).map(row => row[0]).filter(who => names.indexOf(who) == -1);
range.createFilter();
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues([...new Set(hiddenNames)]).build();
sh.getFilter().setColumnFilterCriteria(col, criteria);
}
const countNotOccurrences = (arr, val) => arr.reduce((a, v) => (v !== val ? a + 1 : a), 0);
Driver Data
function MyFunction() {
const ss = SpreadsheetApp.getActive()
const sh = ss.getSheetByName('Sheet0');
const osh = ss.getSheetByName('Sheet1');
osh.clearContents();
const sr = 3;
const dA = sh.getRange(1,1,2).getValues().flat();
const name = dA[0] + ' ' + dA[1];
const nameColumn = 1;
const vo = sh.getRange(sr,1,sh.getLastRow() - sr + 1, sh.getLastColumn()).getValues().filter(r => r[nameColumn -1] == name);
osh.getRange(1,1,vo.length,vo[0].length).setValues(vo);
}
It can be something like this probably:
function onEdit(e) {
if (e.range.columnStart > 1) return;
if (e.range.rowStart > 2) return;
filter_table(e.value);
}
function filter_table(name) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(3,1,sheet.getLastRow(),3);
var data = range.getValues();
var hidden_values = data.map(x => x[0]).filter(x => x != name);
var filter = sheet.getFilter();
if (filter !== null) filter.remove();
range.createFilter();
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(hidden_values).build();
sheet.getFilter().setColumnFilterCriteria(1, criteria);
}
It filteres the range A3:C every time you edit cell A1 or cell A2.
But I'm not sure though what do you want to get when the two cells contain different names.
Update
Here is the 'multi-filter' solution :
function onEdit(e) {
if (e.range.columnStart > 1) return;
if (e.range.rowStart > 2) return;
var sheet = SpreadsheetApp.getActiveSheet();
if(sheet.getName() != 'Filter') return; // <-- to limit the trigger only one sheet 'Filter'
var range = sheet.getRange(1,1,sheet.getLastRow(),3);
var [name1, name2, ...data] = range.getValues();
var hidden_values = data.map(x => x[0])
.filter(x => x != name1[0] && x != name2[0]);
var filter = sheet.getFilter();
if (filter !== null) filter.remove();
range.offset(2,0).createFilter();
if (name1[0] + name2[0] == '') return;
var criteria = SpreadsheetApp.newFilterCriteria()
.setHiddenValues(hidden_values).build();
sheet.getFilter().setColumnFilterCriteria(1, criteria);
}
If both of the cells are empty you will see all the rows.

I want to get a timestamp on edit in my datetime row, but I need it to also timestamp when I copy/paste multiple rows in google script

I'm trying to add timestamps to my datetime row on edit. What I'm getting right now is if one row is edited at a time it works. However, what I need is to timestamp every row when I copy/paste values in over multiple rows.
function getDatetimeCol(){
var SHEET_NAME = 'Queue';
var DATETIME_HEADER = 'datetime (+48h for archive)';
var headers = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).getDataRange().getValues().shift();
var colindex = headers.indexOf(DATETIME_HEADER);
return colindex+1;}
function onEdit(e) {
var SHEET_NAME = 'Queue';
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
var datecell = ss.getRange(cell.getRowIndex(), getDatetimeCol());
if (ss.getName() == SHEET_NAME && cell.getColumn() == 1 && !cell.isBlank() && datecell.isBlank()) {
datecell.setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm");
}
};
function onEdit(e) {
//e.source.toast('entry');
const sh = e.range.getSheet();
if (sh.getName() == 'Queue' && e.range.columnStart == 1) {
//e.source.toast('cond');
let col = {};
sh.getRange(1, 1, 1, sh.getLastColumn()).getValues()[0].forEach((h, i) => { col[h] = i + 1 });
for (var i = 0; i < e.range.rowEnd - e.range.rowStart + 1; i++) {
let rg = sh.getRange(e.range.rowStart + i, col['datetime (+48h for archive)']);
if (rg.isBlank() && sh.getRange(e.range.rowStart,1).getValue() != '') {
//e.source.toast('if');
rg.setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm");
}
}
}
}

Google script getting error while putting multiple conditions

I have pasted example below
code:
function ck() {
//assigning variables
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var lastrow = ss.getLastRow();
var valsr7 = sheet.getRange(lastrow, 3).getValue();
var valsr30 = sheet.getRange(lastrow, 4).getValue();
var valsrn = sheet.getRange(lastrow, 5).getValue();
var valINC7 = sheet.getRange(lastrow, 6).getValue();
var valINC30 = sheet.getRange(lastrow, 7).getValue();
var valINCn = sheet.getRange(lastrow, 8).getValue();
var service = sheet.getRange(lastrow, 2).getValue();
var now = new Date();
var wk = now.getWeek();
//now assigning values to variable
var A = valsr7;
var B = valsr30;
var C = valsrn;
var D = valINC7;
var E = valINC30;
var F = valINCn;
var AB = AB;
if (service == 'Global-Servicenow-Support-T2' && A ==0 && B == 0 ){
MailApp.sendEmail({
to: "prathamesh.padosakar.ext#lafargeholcim.com",
subject : "Open Tickets Global-C&k-T2 - Week-"+wk+"",
htmlBody: "Dear ABC, "+
"<p>Not assigned to any one = "+C+""+
"<P>   "+" "+
"<p>Not updated more than 7 Days = "+D+" "+
"<p>Not Updated more than 30 Days = "+E+""+
"<p>Not assigned to any one = "+F+""+
"<p>   "+" "+
"<p>Best Regards,"+
"<br>Global Service Desk "+,
cc: "techno.pratham94#gmail.com"})
}
if(service == 'Global-Servicenow-Support-T2' && A == 0){
MailApp.sendEmail({
to: "prathamesh.padosakar.ext#lafargeholcim.com",
subject : "Open Tickets Global-C&k-T2 - Week-"+wk+"",
htmlBody: "Dear ABC, "+
"<p>Not Updated more than 30 Days = "+B+""+
"<p>Not assigned to any one = "+C+""+
"<P>   "+" "+
"<p>Not updated more than 7 Days = "+D+" "+
"<p>Not Updated more than 30 Days = "+E+""+
"<p>Not assigned to any one = "+F+""+
"<p>   "+" "+
"<p>Best Regards,"+
"<br>Global Service Desk "+,
cc: "techno.pratham94#gmail.com"
});
}
else {
}
if(service == 'Global-Servicenow-Support-T2' && B == 0){
MailApp.sendEmail({
to: "prathamesh.padosakar.ext#lafargeholcim.com",
subject : "Open Tickets Global-C&k-T2 - Week-"+wk+"",
htmlBody: "Dear ABC, "+
"<p>Not updated more than 7 Days = "+A+" "+
"<p>Not assigned to any one = "+C+""+
"<P>   "+" "+
"<p>Not updated more than 7 Days = "+D+" "+
"<p>Not Updated more than 30 Days = "+E+""+
"<p>Not assigned to any one = "+F+""+
"<p>   "+" "+
"<p>Best Regards,"+
"<br>Global Service Desk "+,
cc: "techno.pratham94#gmail.com"
});
}
else {
}
when i pass condition through if(service == 'Global-Servicenow-Support-T2' && A == 0) and if(service == 'Global-Servicenow-Support-T2' && B == 0) it gives me single output output or correct output . when i pass condition if (service == 'Global-Servicenow-Support-T2' && A ==0 && B == 0 ) it give me output of all 3 conditions which are mention below.
if(service == 'Global-Servicenow-Support-T2' && A == 0) and if(service == 'Global-Servicenow-Support-T2' && B == 0) and if (service == 'Global-Servicenow-Support-T2' && A ==0 && B == 0 )
Please help i want single output when i pass condition if (service == 'Global-Servicenow-Support-T2' && A ==0 && B == 0 ).
Change condition
if(service == 'Global-Servicenow-Support-T2' && A == 0){
to
if(service == 'Global-Servicenow-Support-T2' && A == 0 && B != 0){
and change condition
if(service == 'Global-Servicenow-Support-T2' && B == 0){
to
if(service == 'Global-Servicenow-Support-T2' && B == 0 && A != 0){
Then you will have one output for if (service == 'Global-Servicenow-Support-T2' && A ==0 && B == 0 )

Google Apps Script spreadsheet date manipulation

I have three scripts that are in a google docs spreadsheet. In this spreadsheet, in column H (or column 8), if I type an "x", the script changes it into that days date. After a few days, every date in column H has changed from a date to just a number. The numbers look like this: 40492, 40494, 40511. I am not sure what is causing this. Maybe it's something that is wrong in my script. I've pasted them below. Any ideas?
function onEdit(e) {
var colorA = "yellow";
var colorB = "#dddddd";
var colorC = "#dddddd";
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Purchase Orders");
var range = e.source.getActiveRange();
var sheetName = SpreadsheetApp.getActiveSheet().getName();
if (sheetName == "Purchase Orders") {
// 3 is column C
if (range.getColumn() == 3 && range.getValue() != "") {
sheet.insertRowAfter(range.getRow());
var r = range.getRow() + 1;
sheet.getRange("A" + r + ":H" + r).setBackgroundColor(colorC);
}
}
var col = e.source.getActiveRange().getColumn();
if(col == 3 || col == 8) {
var rows = sheet.getMaxRows();
//column C
var rangeC = sheet.getRange("C1:C"+rows);
var valuesC = rangeC.getValues();
//column H range
var rangeH = sheet.getRange("H1:H"+rows);
var colorH = rangeH.getBackgroundColors();
var valuesH = rangeH.getValues();
//iterate over each row in column C and H
//then change color
for (var row = 0; row < valuesC.length; row++) {
//check for columnC and column H
var hRow = colorH[row];
if (valuesC[row][0] != "" && valuesH[row][0] == "") {
hRow[0] = colorA;
} else if (valuesH[row][0] != "") {
hRow[0] = colorB;
}
}
sheet.getRange("H1:H" + rows).setBackgroundColors(colorH);
}
}
And this one
function onEdit(e) {
var ss = e.source.getActiveSheet();
var r = e.source.getActiveRange();
// 1 is A, 2 is B, ... 8 is H
if (r.getColumn() == 8 && r.getValue() == "x") {
r.setValue(Utilities.formatDate(new Date(), "MST", "yyyy-MM-dd"));
}
}
And this last one
ss = SpreadsheetApp.getActiveSpreadsheet();
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "New PO", functionName: "NewPO"}];
ss.addMenu("New PO", menuEntries);
}
function NewPO() {
SpreadsheetApp.getActiveSheet().insertRowsBefore(1,6);
// Adjust this range accordingly, these are the cells that will be
// copied. Format is getRange(startRow, startCol, numRows, numCols)
ss.getSheetByName("PO Form").getRange(1, 1, 6, 8)
.copyTo(SpreadsheetApp.getActiveSheet().getRange(1, 1, 6, 8));
}
In OnEdit, you probably want to set the format for that cell as well. setNumberFormat(numberFormat) appears to be the function you are after.
http://code.google.com/googleapps/appsscript/class_range.html#setNumberFormat