2

I am trying to create a dependent list as described and answered (with a script) here.

I would like to achieve that if selecting a certain value (e.g. "First") from a cell in column 1, then the drop-down options from the next cell in the same row should offer a range of values from the column in a different sheet with the same heading as the value in the first - left - cell (i.e. the first sheet is called "Selector" - in which there are dropdowns, in the second sheet called "KAT" I have the options for these dropdowns). This should then be possible for every row depending on the value of each first cell of the row.

I have tried to use and adapt the suggested script and have reviewed the sample files in the article but I apparently lack some basic understanding of the script to be able to adapt and implement it properly.

Could anybody kindly help me with making this dynamic dropdown work properly?

Just to clarify my final intention: I would like to have this script working first to be able to use it on multiple files. My final goal, though, is to make self-filling dropdown lists and selectors, so that I could simply fill in the data in the "Selector" sheet and would then be able to select these same values later in the cells below (depending on the name (value) of the first cell in the row = first cell of the column holding validation range). I hope to be able to achieve this by using either Pivot table or any other formula in the "KAT" sheet that would aggregate my data from "Selector" sheet and feed them back as drop-down options ...).

Thank you for your help.

See the example sheet here

Code I used (as above):

function onEdit() 
    {
      var ss = SpreadsheetApp.getActiveSpreadsheet(),
          sheet = ss.getActiveSheet(),
          name = sheet.getName();
      if (name != 'Selector') return;
      var range = sheet.getActiveRange(),
          col = range.getColumn();
      if (col != 1) return;
      var val = range.getValue(),
          dv = ss.getSheetByName('KAT'),
          data = dv.getDataRange().getValues(),
          catCol = data[0].indexOf(val),
          list = [];
      Logger.log(catCol)
      for (var i = 1, len = 100; i < len; i++) // Problem is here, you have too many items in list! Cannot have more 500 items for validation
          list.push(data[i][catCol]);
      var listRange = dv.getRange(2,catCol +1,dv.getLastRow() - 1, 1)
      Logger.log(list)
      var cell = sheet.getRange(range.getRow(), col-1)
      var rule = SpreadsheetApp.newDataValidation()
      .requireValueInRange(listRange)   // Use requireValueIn Range instead to fix the problem
      .build();
      cell.setDataValidation(rule);
      Logger.log(cell.getRow())
    }
Gašper
  • 31
  • 1
  • 4
  • Can you add any details like error problem encountered? [How do I ask a good question?](http://stackoverflow.com/help/how-to-ask), [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) Show the community what you have tried. – abielita Oct 01 '18 at 16:16

1 Answers1

2

This question deals with dynamic dropdown lists. A previous question and answer on StackOverflow (Google Sheets - Dependent drop-down lists) were referenced, and code from that answer was being unsuccessfully re-purposed.

The code in the question was not working for one reason: Line 20

var cell = sheet.getRange(range.getRow(), col-1)

In the referenced code, the dropdown list begins in Column F (col=6). The dependant dropdowns ranged to the left so the definition of the dependant column was "col-1". In the questioner's scenario, the dropdown list begins in Column A (col=1) and the dependant dropdowns range from left to right. However, this line of code was not changed to take into account the different layout. Rather than "col-1", it should be "col+1".

Other matters

  • In addition to this, lines 16 and 17 perform a loop to create an array that might be used for the dependant dropdown. However the loop is redundant because the dropdown is actual defined by creating and assigning a range on the "KAT" sheet.
  • Cell A2 of KAT includes a formula:

    =sort(unique(Selector!$A$2:$A),1,true)

    This may appear to be useful because it automatically adds any new dropdown value entered in "Selector" to a list of values in KAT. In reality it is unproductive, because the dependant dropdown build by the code works vertically rather than horizontally. So an additional row added to KAT does not, of itself, contribute to building the dependant dropdown.

The following code works to build the dependant drop down list. I have deliberately left a number of "Logger" entries in the code to assist the questioner in understanding how the code works.

function onEdit() {
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = ss.getActiveSheet();
    var name = sheet.getName();

    if (name != 'Selector') return;
    var range = sheet.getActiveRange();
    var col = range.getColumn();
    var dropdownrow = range.getRow(); // added for debugging and informationm

    if (col != 1) return;

    var val = range.getValue();
    Logger.log("the cursor is in 'Selector' in cell = " + range.getA1Notation()); //DEBUG
    Logger.log("That's row " + dropdownrow + ", and column " + col + ". The value selected = " + val); // DEBUG



    var dv = ss.getSheetByName('KAT');
    var data = dv.getDataRange().getValues();
    var catCol = data[0].indexOf(val);
    var list = [];
    var KAT_data = dv.getDataRange();
    var KAT_data_len = KAT_data.getLastRow(); // added to give 'for' loop a sensible range

    Logger.log("The data range on KAT is " + KAT_data.getA1Notation() + ", and the last row of data = " + KAT_data_len); //DEBUG
    Logger.log("KAT data = '" + data + "'"); // DEBUG
    Logger.log("Found the dropdown cell value of '" + val + "' in KAT as item #" + catCol); //DEBUG

    for (var i = 1, len = KAT_data_len; i < len; i++) { // Irrelevant because the data validation range is obtained by defining a range on KAT

        // Problem is here, the unique command in A2 creates a blank row
        // Logger.log("i="+i+", data = "+data[i][catCol]); // DEBUG
        list.push(data[i][catCol]);

    }

    var listRange = dv.getRange(2, catCol + 1, dv.getLastRow() - 1, 1);
    Logger.log("FWIW, this is the list after the loop= " + list); // DEBUG
    Logger.log("The contents for the new data validation range (taken from KAT) is " + listRange.getA1Notation()); // DEBUG
    Logger.log("The new validation range gets added to col = " + (col + 1)); // DEBUG

    //var cell = sheet.getRange(range.getRow(), col-1); // governs the next validation range. Example validation worked right to left, but this sheet works left to right. So must ADD 1, not subtract 1.
    var cell = sheet.getRange(range.getRow(), col + 1);
    Logger.log("The cell to be assigned the new validation range will be " + cell.getA1Notation()); // DEBUG
    var rule = SpreadsheetApp.newDataValidation().requireValueInRange(listRange).build(); // Build validation rule
    cell.setDataValidation(rule); // assign validation range to new cell

}

Is this code worthwhile?

The code, as written and referenced, is limited to creating only one level of dependant dropdowns. To this extent it has very limited value. A different approach to creating dependant dropdowns is justified.

"How do you do dynamic / dependent drop downs in Google Sheets?" on StackOverflow has been a meeting place for discussing and updating techniques for dynamic dependant dropdowns since 2014. The latest update was in February 2018 by Max Makhrov. Thye code described here may be useful for the questioner.

Tedinoz
  • 5,911
  • 3
  • 25
  • 35