0

How do I create a dynamic dependent dropdown list in Google AppsScript? What I want to achieve is, when I choose PH in order type, the product selection dropdown should have ['PH-Test Product 1', 'PH-Test Product 2', 'PH-Test Product 3'] options. And when I choose EC it should have ['EC-Test Product 1', 'EC-Test Product 2', 'EC-Test Product 3'].

Here's my code-

  1. form.html
<head>
 <base target="_top">
 <?!= include('css_script'); ?>
</head>
<body>
 <div class="container">    
  <div class = "row">
   <h1>A Sample Form</h1>
  </div>
      
  <div id="productsection"></div>
  <div class = "row">   
   <button id="addproduct">Add Product</button>
  </div>                                    <!-- end of row -->
 </div>
 <?!= include('js_script'); ?>
</body>
  1. js_script.html
<script>
  let counter = 0;

  const orderTypeList = ["PH", "EC"];
  const optionListPH = ["PH-Test Product 1", "PH-Test Product 2", "PH-Test Product 3"];
  const optionListEC = ["EC-Test Product 1", "EC-Test Product 2", "EC-Test Product 3"];                                   
  
  document.getElementById("addproduct").addEventListener("click", addInputField);

  function addInputField(){
    counter++;
    
    // creates a new div of class row
    const newDivElem = createElementTemplate('div', `row${counter}`, 'row');

    // creates a new select tag for order type dropdown
    const newOrderTypeSelectElem = createElementTemplate('select', `ordertype${counter}`);

    // function that populates the dropdown for products and is inserted to the above "ordertypeX" select tag
    createOptionsElem(newOrderTypeSelectElem, orderTypeList);

    // creates a new select tag for product dropdown
    const newProductSelectElem = createElementTemplate('select', `product${counter}`);
    
    // Code to switch options depending on ordertype
    //------------------------- Does Not Work --------------------------
    if(document.getElementById(`ordertype${counter}`).value === 'PH'){
      const optionList = optionListPH;
    }else{
      const optionList = optionListEC;
    }
    //------------------------------------------------------------------

    
    // generates the content of the dropdown for products and is inserted to the above "productX" select tag
    createOptionsElem(newProductSelectElem, optionList);
    
    newDivElem.appendChild(newOrderTypeSelectElem);
    newDivElem.appendChild(newProductSelectElem);

    // Finally, appends the newly created div tag to the productSection tag.
    document.getElementById('productsection').appendChild(newDivElem);
  }

function createOptionsElem(selectTag, optionsArr){
  const newDefaultOptionTag = document.createElement('option');
  newDefaultOptionTag.value = "";
  // newDefaultOptionTag.select = false;
  newDefaultOptionTag.textContent="Choose your option"; 
  for(let i in optionsArr){
    const newOptionTag = document.createElement('option');
    newOptionTag.textContent = optionsArr[i];
    newOptionTag.value = optionsArr[i];

    // Inserts the option tag in select tag
    selectTag.appendChild(newOptionTag);
  }
}

// function to create a new element
function createElementTemplate(tagType, idVal, className){
  const newElement = document.createElement(tagType);
  
  if(idVal !== undefined)
    newElement.id = idVal;
  
  if(className !== undefined)
    newElement.classList.add(className);

  return newElement;
}
</script>
  1. css_script.html
<style>
 .row{
   margin-top: 5px;
   margin-bottom: 5px;
 }
</style>
  1. Code.gs
function doGet(e) {
  Logger.log(e);
  return HtmlService.createTemplateFromFile('form_basic').evaluate();
}

function include(fileName){
  return HtmlService.createHtmlOutputFromFile(fileName).getContent();
}
3
  • In your script, it seems that when a button is clicked, 2 dropdown lists are created. About when I choose EC it should have ['EC-Test Product 1', 'EC-Test Product 2', 'EC-Test Product 3'], in your script, when a button is clicked, PH will be used as the 1st value from the created dropdown list. By this, optionList = optionListPH; is always used. So, I cannot understand when I choose EC it should have ['EC-Test Product 1', 'EC-Test Product 2', 'EC-Test Product 3']. Can I ask you about the detail of your goal? Commented Jan 20, 2023 at 6:24
  • @Tanaike What I want is, every time the add product button is clicked, it should create two dropdowns. The second dropdown is dependent on the first dropdown. So when I select PH in first dropdown only the PH Products(from optionListPH) should be displayed in the second dropdown. Similarly, If I choose EC in first dropdown only the EC Products(from optionListEC) should be displayed in the second dropdown. Commented Jan 20, 2023 at 6:31
  • Thank you for replying. From your reply, I proposed a modification point as an answer. Please be careful about this. If that was not useful, I apologize. Commented Jan 20, 2023 at 6:53

1 Answer 1

3

Modification points:

  • In your script, when a button is clicked, 2 dropdown lists are created. By this, at the following script,

      if(document.getElementById(`ordertype${counter}`).value === 'PH'){
        const optionList = optionListPH;
      }else{
        const optionList = optionListEC;
      }
    
    • in the case of your script, optionListPH is always used to the 1st dropdown list.
  • And, when you want to change the 2nd dropdown list by changing the 1st dropdown list, it is required to add more script for checking it.

When these points are reflected in your script, how about the following modification?

From:

// Code to switch options depending on ordertype
//------------------------- Does Not Work --------------------------
if(document.getElementById(`ordertype${counter}`).value === 'PH'){
  const optionList = optionListPH;
}else{
  const optionList = optionListEC;
}
//------------------------------------------------------------------


// generates the content of the dropdown for products and is inserted to the above "productX" select tag
createOptionsElem(newProductSelectElem, optionList);

newDivElem.appendChild(newOrderTypeSelectElem);
newDivElem.appendChild(newProductSelectElem);

// Finally, appends the newly created div tag to the productSection tag.
document.getElementById('productsection').appendChild(newDivElem);

To:

// Code to switch options depending on ordertype
//------------------------- Does Not Work --------------------------
const optionList = optionListPH; // Modified
//------------------------------------------------------------------

// generates the content of the dropdown for products and is inserted to the above "productX" select tag
createOptionsElem(newProductSelectElem, optionList);

newDivElem.appendChild(newOrderTypeSelectElem);
newDivElem.appendChild(newProductSelectElem);

// Finally, appends the newly created div tag to the productSection tag.
document.getElementById('productsection').appendChild(newDivElem);

// I added the below script.
newOrderTypeSelectElem.addEventListener("change", function() {
  newProductSelectElem.innerHTML = "";
  createOptionsElem(newProductSelectElem, this.value === 'PH' ? optionListPH : optionListEC);
});
  • When this modification is reflected in your script, when a button is clicked, 2 dropdown lists are created. And, when 1st dropdown list is changed, the 2nd dropdown list is refreshed with new values.

Note:

  • This modification is for your showing script. When you change your script, this script might not be able to be used. Please be careful about this.
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, your solution works. But, why to do this- const e = document.getElementById(this.id.replace("ordertype", "product"));, instead of just const e = document.getElementById(`product${counter}`); ?
Regarding the above question, I get it now, const e = document.getElementById(product${counter}); will only allow to change the ordertype and products dependency only on the current products not the previously added products. Thanks a lot.
@arnieM Thank you for replying. I'm glad your issue was resolved. I modified the above script. Please confirm it. In this case, I thought that newProductSelectElem might be able to be directly used instead of document.getElementById(this.id.replace("ordertype", "product"));.
Yes, your updated function does work. But can you explain, how does the function identify which select-element to update, as we are not passing any id?
@arnieM Thank you for replying. About can you explain, how does the function identify which select-element to update, as we are not passing any id?, in your script, newProductSelectElem is declared with const newProductSelectElem = createElementTemplate('select', product${counter});. In this case, it seems that the ID is set. I thought that this might be able to be used. If my explanation was not useful, I apologize.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.