I've been trying to make dependent drop down lists using App script. When I select my independent drop down option, executions shows "Completed", yet it won't add in the dependent drop down in the column beside it.
I can't seem to figure out what's going wrong here:
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Exercise Index");
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 1 && activeCell.getRow() > 3 && ss.getSheetName()=="Weekly Template"){
activeCell.offset(0,1).clearContent().clearDataValidations();
var categories = datass.getRange(1,1,1,datass.getLastColumn()).getValues();
var catIndex = categories[0].indexOf(activeCell.getValue())+1;
if(catIndex != 0){
var validationRange = datass.getRange(2,catIndex,datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
activeCell.offset(0,1).setDataValidation(validationRule);
}
}
}
Any help would be greatly appreciated as this is my first go at App Script.
I did manage to get it functioning as intended. Here's the script in case anyone comes across this in the future:
function onEdit(){
var tabLists = "Exercise Index";
var spreadsheet = SpreadsheetApp;
var activeSheet = spreadsheet.getActiveSpreadsheet().getActiveSheet();
var data = spreadsheet.getActiveSpreadsheet().getSheetByName(tabLists);
var activeCell = activeSheet.getActiveCell();
if(activeCell.getColumn() == 1 && activeCell.getRow() > 3 && activeSheet.getSheetName().includes("Week")){
activeCell.offset(0, 1).clearDataValidations();
var makes = data.getRange(1, 1, 1, data.getLastColumn()).getValues();
var makeIndex = makes[0].indexOf(activeCell.getValue()) + 1;
if(makeIndex != 0){
var validationRange = data.getRange(2, makeIndex, data.getLastRow());
var validationRule = spreadsheet.newDataValidation().requireValueInRange(validationRange).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}
Related
I'm trying to connect 2 spreadsheets, such that, I can perform a sumif function on one spreadsheet and get the result on the current one. I'm using onEdit installable trigger on function when since the simple trigger doesn't work. The dependant dropdown and also the sumif through a for loop works, but I can't seem to get the function when to call the function sum in order to set value on a cell. The sum function works separately and gives the result, but when executing onEdit it doesn't.
Also, is this the correct way to execute sumif? Is there any faster way(I require to execute it around 600-1000 times, here I kept it just 10 to test it out, which again is slow)?
My code follows:
'''
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var stck = SpreadsheetApp.openById("1WGbEo1Xr99HwHY_4ZaeTRIgCOuNcjVfqCzZx4dcQX4I");
var unisensor = stck.getSheetByName("Unisensor");
var ssOptions = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Product List");
var options1 = ssOptions.getRange(2,1,ssOptions.getLastRow() - 1,2).getValues();
function When(e){
var activeCell = e.range;
var val = activeCell.getValue();
var r = activeCell.getRow();
var c = activeCell.getColumn();
var ssName = activeCell.getSheet().getName();
if (ssName=="Stock" && r==2 && c==1){
ss.getRange(r,2).clearContent();
ss.getRange(r,2).clearDataValidations();
var filteredOptions = options1.filter(function(o){return o[0] === val});
var listToApply = filteredOptions.map(function(o){return o[1]});
console.log(listToApply);
var cell = ss.getRange(r,2);
applyValidationToCell(listToApply,cell);
}
if (ssName=="Stock" && r==2 && c==2){
var company = ss.getRange(r,1);
if(company ==="Unisensor"){
sum(val);
}
}
}
function applyValidationToCell(list,cell){
var rule = SpreadsheetApp
.newDataValidation()
.requireValueInList(list)
.setAllowInvalid(false)
.build();
cell.setDataValidation(rule);
}
function sum(val){
var res = 0;
var result = ss.getRange(2,3);
for (i =4;i<=10;i++){
var cell = unisensor.getRange(i,3).getValue();
var cellres = unisensor.getRange(i,9).getValue();
if( cell == val){
res+= cellres;
}
}
result.clearContent();
result.setValue(res);
Logger.log(res);
}
'''
Thanks in advance.
If when(e) is being executed without errors, but sum() is not called, this means that your if condition is not fulfilled
Troubleshoot by implementing the following logs:
function When(e){
var activeCell = e.range;
var val = activeCell.getValue();
var r = activeCell.getRow();
var c = activeCell.getColumn();
var ssName = activeCell.getSheet().getName();
if (ssName=="Stock" && r==2 && c==1){
ss.getRange(r,2).clearContent();
ss.getRange(r,2).clearDataValidations();
var filteredOptions = options1.filter(function(o){return o[0] === val});
var listToApply = filteredOptions.map(function(o){return o[1]});
console.log(listToApply);
var cell = ss.getRange(r,2);
applyValidationToCell(listToApply,cell);
}
if (ssName=="Stock" && r==2 && c==2){
console.log('if (ssName=="Stock" && r==2 && c==2)')
var company = ss.getRange(r,1);
if(company ==="Unisensor"){
console.log('company ==="Unisensor"')
sum(val);
}
else{
console.log('NOT company ==="Unisensor"')
}
}
else{
console.log('NOT if (ssName=="Stock" && r==2 && c==2)')
}
}
After the funciton executes on onEdit trigger - view the logs.
I have one workbook with multiple sheets and I've been running some simple scripts on two of those sheets (those sheets are basically copies of one another).
Once script creates a dropdown based on the value entered in one of the cells, while the second script adds a timestamp based on when the new dropdown was edited.
Initially I had two onEdit functions running on the first sheet.
Then I created a copy of these functions, with small amendments, to run on another sheet(same workbook)
Given that I don't really know how to have a separate script per worksheet I now have a one script with 4 similar onEdit functions.
Since I'm a total newbie I'm sure there's a better, more efficient way to write this code.
I'd appreciate your help in optimizing this.
function onEdit(e) {
addTimestamp(e);
addTimestamp2(e);
Dropdown(e);
Dropdown2(e);
}
function addTimestamp(e) {
var startRow = 2;
var targetColumn = 10;
var ws = "Tracker1";
var row = e.range.get.Row();
var col = e.range.getColumn();
if(col === targetColumn && row >= startRow && e.source.getActiveSheet().getName() === ws) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row,11).setValue(currentDate);
}
}
function addTimestamp2(e) {
var startRow = 2;
var targetColumn = 10;
var ws = "Tracker2";
var row = e.range.get.Row();
var col = e.range.getColumn();
if(col === targetColumn && row >= startRow && e.source.getActiveSheet().getName() === ws) {
var currentDate = new Date();
e.source.getActiveSheet().getRange(row,11).setValue(currentDate);
}
}
function Dropdown(){
var tabLists = "StatusFlow";
var tabValidation = "Tracker1"
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabLists);
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 9 && activeCell.getRow() > 1 && ss.getSheetName() == tabValidation){
activeCell.offset(o,1).clearContent().clearDataValidations();
var makes = datass.getRange(1,1,1, datass.getLastColumn()).getValues();
var makeIndex = makes[0].indexOf(activeCell.getValue()) +1;
if(makeIndex !=0) {
var validationRange = datass.getRange(2, makeIndex, datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).setAllowInvalid(false).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}
function Dropdown2(){
var tabLists = "StatusFlow";
var tabValidation = "Tracker2"
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabLists);
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 9 && activeCell.getRow() > 1 && ss.getSheetName() == tabValidation){
activeCell.offset(o,1).clearContent().clearDataValidations();
var makes = datass.getRange(1,1,1, datass.getLastColumn()).getValues();
var makeIndex = makes[0].indexOf(activeCell.getValue()) +1;
if(makeIndex !=0) {
var validationRange = datass.getRange(2, makeIndex, datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).setAllowInvalid(false).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}
here is a more efficient way to replace the two addTimestamp functions:
function onEdit(e) {
var activeSheet = e.source.getActiveSheet();
var activeSName = activeSheet.getName();
var row = e.range.get.Row();
var col = e.range.getColumn();
if ((activeSName == 'Tracker1' || activeSName == 'Tracker2') && col === 10 && row >= 2) {
activeSheet.getRange(row, 11).setValue(new Date());
}
}
You could give the two Dropdown functions a shot and see if you can do something similar. Nothing like learning-by-doing. :-D
Just be careful that in onEdit you are passing e to these Dropdown functions. But not using them in these functions.
This question already has an answer here:
Merging or Combining two onEdit trigger functions
(1 answer)
Closed 2 years ago.
I made a dependent drop-down with a script.
I'd like to apply it to two sheets.
but only OnEdit1 works and onEdit2 doesn't work.
I don't know what to do with both sheets.
Do I have to add or do something to make two sheets work?
function onEdit(e){
oneEdit1(e);
var tabLists = "lists";
var tabValidation = "Question_B";
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabLists);
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 4 && activeCell.getRow() > 1 && ss.getSheetName() == tabValidation){
activeCell.offset(0, 1).clearContent().clearDataValidations();
var makes = datass.getRange(1, 1, 1, datass.getLastColumn()).getValues();
var makeIndex = makes[0].indexOf(activeCell.getValue()) + 1;
if(makeIndex != 0){
var validationRange = datass.getRange(3, makeIndex, datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
oneEdit2(e);
var tabListss = "lists2";
var tabValidations = "Qeustion_R";
var sss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datasss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(tabListss);
var activeCell = sss.getActiveCell();
if(activeCell.getColumn() == 4 && activeCell.getRow() > 1 && ss.getSheetName() == tabValidations){
activeCell.offset(0, 1).clearContent().clearDataValidations();
var makess = datasss.getRange(1, 1, 1, datasss.getLastColumn()).getValues();
var makeIndexs = makess[0].indexOf(activeCell.getValue()) + 1;
if(makeIndex != 0){
var validationRange = datasss.getRange(3, makeIndexs, datasss.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}
Two combine two onEdit functions in one:
define both of them outside of the main function
call them from the main function
Sample:
function onEdit(e){
oneEdit1(e);
oneEdit2(e)
}
function oneEdit1(e){
...
}
function oneEdit2(e){
...
}
I have the following Google Apps onEdit Script which looks up the table in columns A:D in my 'DropDown Lists' sheet. This works for the dropdown in column C of the 'HISOP Training' sheet when the Branch is selected in the dropdown in column A of the same sheet:
//Dynamic Dropdown for HISOP Training
{
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var tablists = 'Dropdown Lists';
var tabValidation = 'HISOP Training';
var ss = spreadsheet.getActiveSheet();
var datass = spreadsheet.getSheetByName(tablists);
var activeCell = ss.getActiveCell();
if (
activeCell.getColumn() == 1 &&
activeCell.getRow() > 1 &&
ss.getSheetName() == tabValidation
) {
activeCell
.offset(0, 2)
.clearContent()
.clearDataValidations();
var base = datass.getRange(2, 1, 1, 5).getValues();
var baseIndex = base[0].indexOf(activeCell.getValue()) + 1;
Logger.log(baseIndex);
if (baseIndex != 0) {
//Dynamic dropdown for 'Employee'
var validationRange = datass.getRange(6, baseIndex, 150);
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
activeCell.offset(0, 2).setDataValidation(validationRule);
}
}
if (ss.getSheetName() == tabValidation) {
var lock = LockService.getScriptLock();
if (lock.tryLock(0)) {
autoid_(ss);
lock.releaseLock();
}
}
}
I now also want the dropdown in column D of the 'HISOP Training' sheet to select from the range BO:BR of the 'Dropdown List' sheet when the Branch in Column A of the 'HISOP Training' sheet is selected but I don't know how to write the script for this.
This is an image of my 'HISOP Training' sheet:
This is a link to a sanitised version of my spreadsheet:
Spreadsheet
I would really appreciate some help with this.
Final answer:
function myOnEdit(e){
var sheet = SpreadsheetApp.getActive().getSheetByName('HISOP Training');
var sheet2 = SpreadsheetApp.getActive().getSheetByName('Dropdown Lists');
var value = e.value;
var col = e.range.getColumn();
var row = e.range.getRow();
if(col==1 && e.range.getValue()=='New York' && row>2 && e.range.getSheet().getName()=='HISOP Training'){
// 2 is for dropdown D
var dropdownData = sheet2.getRange("A6:A150").getValues().flat();
var dropdownData2 = sheet2.getRange("BO4:BO150").getValues().flat();
var allowDropdown = sheet.getRange(row, col+2).clearDataValidations().clearContent();
var allowDropdown2 = sheet.getRange(row, col+3).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
var rule2 = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData2, true).build();
allowDropdown.setDataValidation(rule);
allowDropdown2.setDataValidation(rule2);
}
if(col==1 && e.range.getValue()=='London' && row>2 && e.range.getSheet().getName()=='HISOP Training'){
var dropdownData = sheet2.getRange("B6:B150").getValues().flat();
var dropdownData2 = sheet2.getRange("BP4:BP150").getValues().flat();
var allowDropdown = sheet.getRange(row, col+2).clearDataValidations().clearContent();
var allowDropdown2 = sheet.getRange(row, col+3).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
var rule2 = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData2, true).build();
allowDropdown.setDataValidation(rule);
allowDropdown2.setDataValidation(rule2);
}
if(col==1 && e.range.getValue()=='Paris' && row>2 && e.range.getSheet().getName()=='HISOP Training'){
var dropdownData = sheet2.getRange("C6:C150").getValues().flat();
var dropdownData2 = sheet2.getRange("BQ4:BQ150").getValues().flat();
var allowDropdown = sheet.getRange(row, col+2).clearDataValidations().clearContent();
var allowDropdown2 = sheet.getRange(row, col+3).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
var rule2 = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData2, true).build();
allowDropdown.setDataValidation(rule);
allowDropdown2.setDataValidation(rule2);
}
if(col==1 && e.range.getValue()=='Tokyo' && row>2 && e.range.getSheet().getName()=='HISOP Training'){
var dropdownData = sheet2.getRange("D6:D150").getValues().flat();
var dropdownData2 = sheet2.getRange("BR4:BR150").getValues().flat();
var allowDropdown = sheet.getRange(row, col+2).clearDataValidations().clearContent();
var allowDropdown2 = sheet.getRange(row, col+3).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
var rule2 = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData2, true).build();
allowDropdown.setDataValidation(rule);
allowDropdown2.setDataValidation(rule2);
}
}
Solution
From my interpretation of your question you want to be able to only select a dropdrown of values in columns C and D only if a specific value is selected in column A. To provide a solution to this question instead of providing a specific answer to your sheet case I have provided a general solution abstracting the question so that others with similar questions can easily interpolate the answer and use it as well. You will just need to adapt this answer to you case.
To achieve this I have set up a conditional on an onEdit function to catch changes in the sheet and if this conditional is met (in your case if the branch in column A is selected) then you will be able to select from C and D dropdowns. The following code that solves the issue has self explanatory comments:
function onEdit(e) {
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
// Get the value of the cell changed
var value = e.value;
// Get col and row of the cell changed to make sure it was in col A
var col = e.range.getColumn();
var row = e.range.getRow();
// If col A. Here you could also add another condition to the if for instance if the value on col A
// is equal to whatever value you want to select in the dropdown in A, then execute this
if(col==1 && e.range.getValue()=='VALUE 1'){
// Get the data for the range of the dropdown. Here you choose if you want to insert dropdowns for C and D
var dropdownData = sheet.getRange("C1:C5").getValues().flat();
// Get the cell we will let the dropdown go (clear all previous content and data validations)
// In your case these you be the columns D and
var allowDropdown = sheet.getRange(row, col+1).clearDataValidations().clearContent();
// Create rules for the respective dropdowns of C and D (in this case is just one rule because I am
// just using a single dropdown to exemplify how to do this
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
// Set the data validation
allowDropdown.setDataValidation(rule);
}
// SECOND RANGE. REPEAT FOR THE REST IF WE HAVE MORE SUB RANGES
if(col==1 && e.range.getValue()=='VALUE 2'){
var dropdownData = sheet.getRange("D1:D5").getValues().flat();
var allowDropdown = sheet.getRange(row, col+1).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
allowDropdown.setDataValidation(rule);
}
}
And this is how this example would look like in the sheet:
As you seem to have difficulties understanding, I have adjusted the general case scenario to your specific situation and I have done for you both the right dropdowns for columns C and D. These are as follow:
function onEdit(e) {
var sheet = SpreadsheetApp.getActive().getSheetByName('HISOP Training');
var sheet2 = SpreadsheetApp.getActive().getSheetByName('Dropdown Lists');
var value = e.value;
var col = e.range.getColumn();
var row = e.range.getRow();
if(col==1 && e.range.getValue()=='New York' && row>2 && e.range.getSheet().getName()=='HISOP Training'){
// 2 is for dropdown C
var dropdownData = sheet2.getRange("BO4:BO49").getValues().flat();
var dropdownData2 = sheet2.getRange("Z2:Z4").getValues().flat();
var allowDropdown = sheet.getRange(row, col+3).clearDataValidations().clearContent();
var allowDropdown2 = sheet.getRange(row, col+2).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
var rule2 = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData2, true).build();
allowDropdown.setDataValidation(rule);
allowDropdown2.setDataValidation(rule);
}
if(col==1 && e.range.getValue()=='London' && row>2 && e.range.getSheet().getName()=='HISOP Training'){
var dropdownData = sheet.getRange("BP4:BP45").getValues().flat();
var dropdownData2 = sheet2.getRange("AA2:AA3").getValues().flat();
var allowDropdown = sheet.getRange(row, col+1).clearDataValidations().clearContent();
var allowDropdown2 = sheet.getRange(row, col+2).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
var rule2 = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData2, true).build();
allowDropdown.setDataValidation(rule);
allowDropdown2.setDataValidation(rule);
}
if(col==1 && e.range.getValue()=='Paris' && row>2 && e.range.getSheet().getName()=='HISOP Training'){
var dropdownData = sheet.getRange("BQ4:BQ43").getValues().flat();
var dropdownData2 = sheet2.getRange("AB2:AB4").getValues().flat();
var allowDropdown = sheet.getRange(row, col+1).clearDataValidations().clearContent();
var allowDropdown2 = sheet.getRange(row, col+2).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
var rule2 = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData2, true).build();
allowDropdown.setDataValidation(rule);
allowDropdown2.setDataValidation(rule);
}
if(col==1 && e.range.getValue()=='Tokyo' && row>2 && e.range.getSheet().getName()=='HISOP Training'){
var dropdownData = sheet.getRange("BR4:BR33").getValues().flat();
var dropdownData2 = sheet2.getRange("AC2:AC3").getValues().flat();
var allowDropdown = sheet.getRange(row, col+1).clearDataValidations().clearContent();
var allowDropdown2 = sheet.getRange(row, col+2).clearDataValidations().clearContent();
var rule = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData, true).build();
var rule2 = SpreadsheetApp.newDataValidation().requireValueInList(dropdownData2, true).build();
allowDropdown.setDataValidation(rule);
allowDropdown2.setDataValidation(rule);
}
}
I hope this has helped you. Let me know if you need anything else or if you did not understood something. :)
trying to get a script to only run on one tab, rather than impact all tabs - this one seems to be having an impact across multiple tabs for some reason.
Have tried declaring the name of the tab, which in this case would be:
"1. Scheduling"
but it breaks down and I get errors when trying to run the script. Any ideas?
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var datass = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("3. Current_Team")
var activeCell = ss.getActiveCell();
if(activeCell.getColumn() == 4 && activeCell.getRow() > 1){
activeCell.offset(0, 1).clearContent().clearDataValidations();
var makes = datass.getRange(1, 1, 1, datass.getLastColumn()).getValues();
var makeIndex = makes[0].indexOf(activeCell.getValue()) + 1;
if(makeIndex != 0) {
var validationRange = datass.getRange(3, makeIndex, datass.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
activeCell.offset(0, 1).setDataValidation(validationRule);
}
}
}
Try this:
function onEdit(e){
var sh=e.range.getSheet();
if(sh.getName()!='1. Scheduling')return;
var datash=e.source.getSheetByName("3. Current_Team")
if(e.range.columnStart==4 && e.range.rowStart>1){
e.range.offset(0, 1).clearContent().clearDataValidations();
var makes=datash.getRange(1, 1, 1, datash.getLastColumn()).getValues();
var makeIndex=makes[0].indexOf(e.value) + 1;
if(makeIndex != 0) {
var validationRange = datash.getRange(3, makeIndex, datash.getLastRow());
var validationRule = SpreadsheetApp.newDataValidation().requireValueInRange(validationRange).build();
e.range.offset(0, 1).setDataValidation(validationRule);
}
}
}