Home > Software engineering >  Dropdown list apply more than edited row in appscript
Dropdown list apply more than edited row in appscript

Time:01-12

First I am so sorry for my English Skill I have to use my poor English Skill to make this question. I made a script to apply Depended Data Validation on Column E of Orders Sheet when new SKU added to Column D, like when I add 1 SKU to D2, E2 will show dropdown list with all Supplier that SKU have (ex: SKU00124 have Amazon, Walmart, Chewy as supplier if I input SKU00124 to D2, E2 will show dropdown list with Amazon, Walmart, Chewy option for user choice, and SKU00122 have only Walmart, Amazon when I input SKU00122 to D3, E3 will show Walmart, Amazon). SKU and Supplier Store at Item_List sheet with SKU at column B and supplier at Column E. My issue is in Orders sheet column D where to store SKU, it get data from Draft_Order column AA, I am using a formula to get values of AA input to D.

={"SKU";ARRAYFORMULA(if(B2:B="","",'Draft_Order'!AA2:AA))}

I see the script does not work correctly, I have to delete values in column D and when the formula gets values again the script runs. But it not set Data Validation to all range Ex: If SKU input from D2:D20, it not apply data validation to E2:E20, script just applies it row by row and only apply for 5 row (means only E2:E7 applied data validation), if I want more I have to delete the rest of SKU.

I use onEdit(e) to catch cell edited on column D

Here is my example spreadsheet: My Spreadsheet here

Here is my script:

function onEdit(e) {
  // Get the active sheet
  var sheet = e.source.getActiveSheet();

  // Check if the active sheet is the "Order" sheet
  if (sheet.getSheetName() == "Order") {
    // Get the range that was edited
    var range = e.range;

    // Get the column of the edited cell
    var col = range.getColumn();

    // Check if the edited cell is in column D
    if (col == 4) {
      // Get the values in the edited range
      var values = range.getValues();

      // Loop through the values in the range
      for (var i = 0; i < values.length; i  ) {
        for (var j = 0; j < values[i].length; j  ) {
          // Check if the value is not empty
          if (values[i][j] != "") {
            // Get the SKU
            var sku = values[i][j];

            // Get the sources for the SKU using the getSources function
            var sources = getSources(sku);

            // Check if there are any sources for the SKU
            if (sources.length > 0) {
              // Calculate the row and column of the current cell
              var row = range.getRow()   i;
              var col = range.getColumn()   1;

              // Get the cell in column E
              var cell = sheet.getRange(row, col);

              // Set the data validation for the cell using the sources list
              cell.setDataValidation(SpreadsheetApp.newDataValidation().setAllowInvalid(true).requireValueInList(sources).build());
            }
          }
        }
      }
    }
  }
}

function getSources(sku) {
  // Get the active spreadsheet
  var ss = SpreadsheetApp.getActiveSpreadsheet();

  // Get the "Item List sheet
  var sheet = ss.getSheetByName("Item List");

  // Get the data in the sheet
  var data = sheet.getDataRange().getValues();

  // Create an array to store the sources
  var sources = [];

  // Loop through the data in the sheet
  for (var i = 0; i < data.length; i  ) {
    // Check if the SKU in column B matches the input SKU
    if (data[i][1] == sku) {
      // Add the source in column E to the sources array
      sources.push(data[i][4]);
    }
  }

  // Return the sources array
  return sources;
}

I am trying to fix it by using a range define and apply validation for range length by using edit values.length but script applies data validation for a range more than SKU range. Looks like if SKU values from D2:D20, the dropdown list will show on E2:E35 when D21:D35 is blank and does not have any SKU and issue I got in first script still meets (only E2:E7 is correct values of data validation, if I need more I have to delete it again.

Here is my try:

function onEdit(e) {
  var sheet = e.source.getActiveSheet();
  if (sheet.getSheetName() == "Order") {
    var range = e.range;
    var col = range.getColumn();
    if (col == 4) {
      var values = range.getValues();
      Logger.log("values.length: "   values.length);
      for (var i = 0; i < values.length; i  ) {
        for (var j = 0; j < values[i].length; j  ) {
          if (values[i][j] != "") {
            var sku = values[i][j];
            var sources = getSources(sku);
            if (sources.length > 0) {
              var row = range.getRow()   i;
              var col = range.getColumn()   1;
              var dataValidation = SpreadsheetApp.newDataValidation().setAllowInvalid(true).requireValueInList(sources).build();
              // Apply data validation to the range of cells in column E
              var numRows = values.length;
              for (var k = 0; k < numRows; k  ) {
                if (values[k][0] == "") {
                  numRows--;
                }
              }
              var validationRange = sheet.getRange(row, col, numRows, 1);
              validationRange.clearDataValidations().clearContent();
              validationRange.setDataValidation(dataValidation);
              Logger.log("numRows: "   numRows);
            }
          }
        }
      }
    }
  }
}

As you see, I try to Logger.log numRow and value.lenght but after script run nothing show

please help me:

1/ script will run each time when I input SKU to AA column at Draft_Orders sheet

2/ Script will run when I input many SKU in 1 times like more than 100 SKU

3/ Script will apply to correct range (SKU have in D2:D100 E2:E100 have data validation not E2:E250

CodePudding user response:

The onEdit() trigger works when the user edits the range. In this case you need to validate when edit has been done in the main sheet where you're getting the data from. You will need to validate whenever the user edits column AA in sheet Draft Order. To give you an idea, check this script (make sure the ranges and sheet name matches with yours):

function onEdit(e) {
  var sheet = e.source.getActiveSheet();
  if (sheet.getSheetName() == "Draft Order") {
    var range = e.range;
    var col = range.getColumn();
    if (col == 27) {
      var values = range.getValues();
      Logger.log("values.length: "   values.length);
      for (var i = 0; i < values.length; i  ) {
        for (var j = 0; j < values[i].length; j  ) {
          if (values[i][j] != "") {
            var sku = values[i][j];
            var sources = getSources(sku);
            if (sources.length > 0) {
              var row = range.getRow()   i;
              var col = range.getColumn()   1;
              var dataValidation = SpreadsheetApp.newDataValidation().setAllowInvalid(true).requireValueInList(sources).build();
              // Apply data validation to the range of cells in column E
              var numRows = values.length;
              for (var k = 0; k < numRows; k  ) {
                if (values[k][0] == "") {
                  numRows--;
                }
              }
              var validationRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Orders").getRange(row, 5);
              validationRange.clearDataValidations().clearContent();
              validationRange.setDataValidation(dataValidation);
              Logger.log("numRows: "   numRows);
            }
          }
        }
      }
    }
  }
}

References: onEdit()

  • Related