Search code examples
google-apps-scriptgoogle-sheetsphpexcelexport-to-excelgoogle-query-language

filter values based on line items with data validation in Google sheet


Data set 1

P1 Type Size Color Material Length
Kurta Pyjamas No Sizeethnic_1 Colorethnic_1 Materialethnic_3 Lengthethnic_1
Dhotis Typethnic_1 No Colorethnic_2 Materialethnic_2 No
Sherwani No No Colorethnic_2 No Lengthethnic_2
Men Pyjamas Typeethnic_2 No Colorethnic_2 No No
Kurtas No Sizeethnic_2 Colorethnic_1 No Lengthethnic_1
Ethnic Jackets No No Colorethnic_1 No No

Data set 2

Typethnic_1 Typeethnic_2 Sizeethnic_1 Sizeethnic_2 Colorethnic_1 Colorethnic_2 Materialethnic_3 Materialethnic_2 Lengthethnic_1 Lengthethnic_2
Mundu Churidar XS XS Beige Green Blended Silk Blend Above Knee Short
Regular Dhoti Regular Pyjama S S Black Grey Cotton Velevt Ankle Length Medium
Patiala M M Blue Maroon Dupion Viscose Rayon
Jodhpuri L L Brown Multi Wool
Harem XL XL Copper Mustard
XXL XXL Cream
3XL 3XL Gold

Problem Statement – Data set 1 has Named Ranges as drop down that holds values from Data set 2 where "Named Ranges" are created. I want to derive the values based on items from Column "P1" that sits within Data set 1.

What I am trying to Achieve – I aim to derive values based on items from Column "P1" that sits within Data set 1 and exclude "No" as values if they exist in these columns (P1, Type, Size, Color, Material, Length) for that particular line item ( Kurta Pyjamas, Dhotis, Sherwani, Men Pyjamas, Kurtas, Ethinic Jackets).

Expected result:

You can also see the small video of the desired output:

https://www.loom.com/share/4bc25874003448cc91fc3dc9a69c4a63

enter image description here

Selecting Dhoti

enter image description here

I am also posting an example google sheet with data set.

https://docs.google.com/spreadsheets/d/18guAXXjWIMDQilX8Z0Y4_Avogjs2ESMbrZY7Sb9TaxE/edit?usp=sharing

Any thoughts or solution will be welcome.


Solution

  • Providing Data Validation using onEdit Trigger

    function loadObjectsAndCreateProductDropDown() {
      const ss = SpreadsheetApp.getActive();
      const sh = ss.getSheetByName('Sheet0');
      const psh = ss.getSheetByName('Sheet1');
      const [ph, ...prds] = sh.getRange(1, 1, 10, 6).getValues().filter(r => r[0]);
      const [ch, ...chcs] = sh.getRange(11, 1, 10, 10).getValues().filter(r => r.join());
      let pidx = {};
      ph.forEach((h, i) => { pidx[h] = i });
      let prd = { pA: [] };
      prds.forEach(r => {
        if (!prd.hasOwnProperty(r[0])) {
          prd[r[0]] = { type: r[pidx['Type']], size: r[pidx['Size']], color: r[pidx['Color']], material: r[pidx['Material']], length: r[pidx['Length']] };
          prd.pA.push(r[0]);
        }
      });
      let cidx = {};
      let chc = {};
      ch.forEach((h, i) => { cidx[h] = i; chc[h] = [] });
      chcs.forEach(r => {
        r.forEach((c, i) => {
          if (c && c.length > 0) chc[ch[i]].push(c)
        })
      })
      const ps = PropertiesService.getScriptProperties();
      ps.setProperty('product_matrix', JSON.stringify(prd));
      ps.setProperty('product_choices', JSON.stringify(chc));
      Logger.log(ps.getProperty('product_matrix'));
      Logger.log(ps.getProperty('product_choices'));
      psh.getRange('A2').setDataValidation(SpreadsheetApp.newDataValidation().requireValueInList(prd.pA).build());
    }
    
    //I chose to use an installable dropdown.  I'm not sure if it's needed.  Its up to you.
    
    function onMyEdit(e) {
      //e.source.toast('entry')
      const sh = e.range.getSheet();
      if (sh.getName() == 'Sheet1' && e.range.columnStart == 1 && e.range.rowStart == 2 && e.value) {
        //e.source.toast('flag1');
        sh.getRange('C2:G2').clearDataValidations();
        let ps = PropertiesService.getScriptProperties();
        let prodObj = JSON.parse(ps.getProperty('product_matrix'));//recovering objects from PropertiesService
        let choiObj = JSON.parse(ps.getProperty('product_choices'));
        let hA = sh.getRange(1, 1, 1, sh.getLastColumn()).getDisplayValues().flat();
        let col = {};
        hA.forEach((h, i) => { col[h.toLowerCase()] = i + 1 });
        ["type", "size", "color", "material", "length"].forEach(c => {
          if (choiObj[prodObj[e.value][c]]) {
            sh.getRange(e.range.rowStart, col[c]).setDataValidation(SpreadsheetApp.newDataValidation().requireValueInList(choiObj[prodObj[e.value][c]]).build());
          }
        })
      }
    }
    

    You could try it this way but I'm guessing you want something different.

    function onMyEdit(e) {
      //e.source.toast('entry')
      const sh = e.range.getSheet();
      if (sh.getName() == 'Sheet1' && e.range.columnStart == 1 && e.range.rowStart == 2 && e.value) {
        //e.source.toast('flag1');
        sh.getRange('C2:G2').clearDataValidations();
        let ps = PropertiesService.getScriptProperties();
        let prodObj = JSON.parse(ps.getProperty('product_matrix'));//recovering objects from PropertiesService
        let choiObj = JSON.parse(ps.getProperty('product_choices'));
        let hA = sh.getRange(1, 1, 1, sh.getLastColumn()).getDisplayValues().flat();
        let col = {};
        hA.forEach((h, i) => { col[h.toLowerCase()] = i + 1 });
        ["type", "size", "color", "material", "length"].forEach(c => {
          if (choiObj[prodObj[e.value][c]]) {
            sh.getRange(e.range.rowStart, col[c]).setDataValidation(SpreadsheetApp.newDataValidation().requireValueInList(choiObj[prodObj[e.value][c]]).build()).offset(-1,0).setFontColor('#000000');
          } else {
            sh.getRange(e.range.rowStart, col[c]).offset(-1,0).setFontColor('#ffffff');
          }
        })
      }
    }
    

    This version actually hides the columns too

    function onMyEdit(e) {
      //e.source.toast('entry')
      const sh = e.range.getSheet();
      if (sh.getName() == 'Sheet1' && e.range.columnStart == 1 && e.range.rowStart == 2 && e.value) {
        //e.source.toast('flag1');
        sh.getRange('C2:G2').clearDataValidations();
        let ps = PropertiesService.getScriptProperties();
        let prodObj = JSON.parse(ps.getProperty('product_matrix'));//recovering objects from PropertiesService
        let choiObj = JSON.parse(ps.getProperty('product_choices'));
        let hA = sh.getRange(1, 1, 1, sh.getLastColumn()).getDisplayValues().flat();
        let col = {};
        hA.forEach((h, i) => { col[h.toLowerCase()] = i + 1 });
        ["type", "size", "color", "material", "length"].forEach(c => {
          if (choiObj[prodObj[e.value][c]]) {
            sh.getRange(e.range.rowStart, col[c]).setDataValidation(SpreadsheetApp.newDataValidation().requireValueInList(choiObj[prodObj[e.value][c]]).build()).offset(-1,0).setFontColor('#000000');
            sh.showColumns(col[c])
          } else {
            sh.getRange(e.range.rowStart, col[c]).offset(-1,0).setFontColor('#ffffff');
            sh.hideColumns(col[c]);
          }
        })
      }
    }
    

    Demo:

    enter image description here

    Here's what the last version looks like:

    enter image description here

    This is my Sheet0:

    P1 Type Size Color Material Length
    Kurta Pyjamas Sizeethnic_1 Colorethnic_1 Materialethnic_3 Lengthethnic_1
    Dhotis Typethnic_1 Colorethnic_2 Materialethnic_2
    Sherwani Colorethnic_2 Lengthethnic_2
    Men Pyjamas Typeethnic_2 Colorethnic_2
    Kurtas Sizeethnic_2 Colorethnic_1 Lengthethnic_1
    Ethnic Jackets Colorethnic_1
    Typethnic_1 Typeethnic_2 Sizeethnic_1 Sizeethnic_2 Colorethnic_1 Colorethnic_2 Materialethnic_3 Materialethnic_2 Lengthethnic_1 Lengthethnic_2
    Mundu Churidar XS XS Beige Green Blended Silk Blend Above Knee Short
    Regular Dhoti Regular Pyjama S S Black Grey Cotton Velevt Ankle Length Medium
    Patiala M M Blue Maroon Dupion Viscose Rayon
    Jodhpuri L L Brown Multi Wool
    Harem XL XL Copper Mustard
    XXL XXL Cream
    3XL 3XL Gold