Home > Software engineering >  How to make the materializecss dropdown work when added dynamically
How to make the materializecss dropdown work when added dynamically

Time:01-19

Following is an example of a sample webform I made in Google Apps Script, where I'm trying to dynamically add three select dropdowns and an input element whenever the add button is clicked. The elements should render in following order - dropdown dropdown input dropdown.

I'm using materialize framework for this.

After a lot of trying and going through the materializecss documentation, I was able to render the text input field as expected. But, the dropdowns still won't render. Clearly, I'm making some mistake, cannot figure out what and where.

I'm including the code files-

  1. Code.gs
function doGet(e) {
  Logger.log(e);
  return HtmlService.createTemplateFromFile('form_materialize').evaluate();
}

function include(fileName){
  return HtmlService.createHtmlOutputFromFile(fileName).getContent();
}
  1. form_materialize.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <!-- google font pack link -->
    <link href="https://fonts.googleapis.com/icon?family=Material Icons" rel="stylesheet">
    <!-- Mini materialize.css cdn link -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <?!= include('css_scripts'); ?>
  </head>
  <body>
    <div >
      
      <div class = "row">
        <h1>A Sample Form</h1>
      </div>
      
      <div id="productsection">
        <!-- product details like "Product Type"(dropdown), "Products"(dropdown), "Product Qty"(text input field), "Unit"(dropdown) to be added here dynamically -->

      </div>

      <div class = "row">
        <a  id="addproduct"><i >add</i></a>
      </div> 

    </div>
    <!-- Mini materialize.js cdn link -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
    <?!= include('js_scripts_materialize'); ?>
  </body>
</html>
  1. js_scripts_materialize.html
<script>
  document.addEventListener('DOMContentLoaded', function() {
    var elems = document.querySelectorAll('select');
    var instances = M.FormSelect.init(elems, options);
  });

  let counter = 0;

  const orderTypeList = ["PH", "ECOM"];
  const optionList = ["Test Product 1", "Test Product 2", "Test Product 3", "Test Product 4", "Test Product 5"];                                   
  const unitOptionList = ["KGS", "PCS", "BAGS"];
  
  document.getElementById("addproduct").addEventListener("click", addInputField);

  function addInputField(){
    counter  ;
    
    // everytime when "add product" button is clicked, the following elements must be added to the "<div id="produc></div>" tag.

    // <div >
    //  <div  id="divone">
      //   <select id="productX">
      //     <option>option-i</option>
      //     <option>option-1</option>
      //     <option>option-2</option>
      //     ...
      //     ...
      //     <option>option-n</option>
    //     <select>
    //  </select>
    //  <div  id="divtwo"> 
    //     <input id="productqtyX" type="text">
    //     <label for="productqtyX">Quantity</label>
    //  </div>
    //  <div  id="divthree"> 
    //     <select id="productUnitX">
    //       <option>option-1</option>
    //       <option>option-2</option>
    //       ...
    //       ...
    //       <option>option-n</option>
    //     </select>
    //  </div>
    // </div>
    
    // creates a new div of class row
    const newDivElem = createElementTemplate('div', null, ['row']);

    // creates a new select tag for order type dropdown
    const newOrderTypeSelectElem = createElementTemplate('select', "ordertype"   counter.toString());

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

    // creates a new select tag for product dropdown
    const newProductSelectElem = createElementTemplate('select', "product"   counter.toString());

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

    // creates a input element for quantity input
    const newQtyInputElem = createElementTemplate('input', 'productqty'   counter.toString(), ['validate']);
    newQtyInputElem.type = 'text';

    // creates a label for the quantity input element
    const newQtyLabelElem = createElementTemplate('label');
    newQtyLabelElem.textContent = "Quantity";

    //Creates a new select element for product quantity unit(dropdown)
    const newUnitSelectElem = createElementTemplate('select', 'productqtyunit'   counter.toString());

    // generates the content of the dropdown for units and is inserted to the above "productqtyunitX" select tag
    createOptionsElem(newUnitSelectElem, unitOptionList);

    //create inner "div" tags with class "input-field col s4" as described in materializecss documentation
    const innerDivElems = [];

    for(let i = 0; i < 4; i  ){
      innerDivElems.push(createElementTemplate('div', `div${(Number(i)   1)}`, ['input-field', 'col', 's3']));
    }
    
    innerDivElems[0].appendChild(newOrderTypeSelectElem);

    innerDivElems[1].appendChild(newProductSelectElem);

    innerDivElems[2].appendChild(newQtyInputElem);
    innerDivElems[2].appendChild(newQtyLabelElem);

    innerDivElems[3].appendChild(newUnitSelectElem);

    //Inserts select, quantityInput, quanityLabel, newUnitSelectTag tags in div child
    for(let i in innerDivElems){
      newDivElem.appendChild(innerDivElems[i]);
    }

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

function createOptionsElem(selectElem, optionsArr){
  const newDefaultOptionElem = document.createElement('option');
  newDefaultOptionElem.disabled = true;
  newDefaultOptionElem.setAttribute('selected', true);
  newDefaultOptionElem.textContent="Choose your option";

  selectElem.appendChild(newDefaultOptionElem);

  for(let i in optionsArr){
    const newOptionElem = document.createElement('option');
    newOptionElem.textContent = optionsArr[i];
    newOptionElem.value = optionsArr[i];

    // Inserts the option tag in select tag
    selectElem.appendChild(newOptionElem);
  }
}

// function to create a new element
function createElementTemplate(tagType, idVal, classNameList){
  const newElement = document.createElement(tagType);
  
  if(idVal !== undefined)
    newElement.id = idVal;
  
  if(classNameList !== undefined){
    for(let i in classNameList){
      newElement.classList.add(classNameList[i]);
    }
  }

  return newElement;
}
</script>

CodePudding user response:

Although I'm not sure whether I could correctly understand your expected result, how about the following modification?

In this modification, your js_scripts_materialize.html is modified.

Modified script:

I think that in this case, this part might not be required to be used.

document.addEventListener('DOMContentLoaded', function() {
  var elems = document.querySelectorAll('select');
  var instances = M.FormSelect.init(elems, options);
});

And also, please modify addInputField() as follows.

From:

document.getElementById('productsection').appendChild(newDivElem);

To:

document.getElementById('productsection').appendChild(newDivElem);
var elems = document.querySelectorAll('select'); // Added
M.FormSelect.init(elems); // Added
  • By this modification, I thought that when you click a red button, you can see the dropdown lists.
  • Related