javascriptgoogle-sheetsgoogle-apps-scriptweb-applicationsmaterialize

Autocomplete MaterializeCSS is not working


I'm trying to create a simple lookup form using Google Apps Script. The form uses data sourced from a spreadsheet to populate a number of autocomplete input fields. I can't figure out why the autocomplete is not working. In supplierIDLookupFormHTML.html I put the script tag for the materialize js file at the very end of the body tag.

The function showSidebar_sellerID() in show_sidebars.js does append a simple div tag to the end of the body tag. But that shouldn't affect the materialze js code, should it?

Here is my code.

supplierIDLookupFormHTML.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <base target="_top">

    <!-- Required meta tags -->
    <meta charset="utf-8">

    <!--Let browser know website is optimized for mobile-->
    <meta id="viewport" content="width=device-width, initial-scale=1.0"/>

    <!--Import Google Icon Font-->
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

    <!--Import materialize.css-->
    <link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"  media="screen,projection"/>

    <!-- Add the standard Google Style Sheet. -->
    <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css"> 

    <!--Import supplierIDLookupFormHTML,css -->
    <?!= HtmlService.createHtmlOutputFromFile('supplierIDLookupFormHTML.css').getContent(); ?>
  </head>
  
  <body>
    <div class="container">
      <!-- <h1>New Customer</h1> -->

      <form id="new-customer-form" onsubmit="onSubmitFormHandler(event)">

        <div class="row">
          <div class="input-field col m6">
              <label for="companyName">Company Name</label>
              <input type="text" id="companyName" name="companyName" class="autocomplete">
          </div>
        </div><!-- end .row -->

        <div class="row">
          <div class="input-field col m6">
              <label for="ebayID">ebayID</label>
              <input type="text" id="ebayID" name="ebayID" class="autocomplete">
          </div>
        </div><!-- end .row -->

        <div class="row">
          <div class="input-field col m6">
              <label for="amazonSellerID">Amazon Seller ID</label>
              <input type="text" id="amazonSellerID" name="amazonSellerID" class="autocomplete">
          </div>
        </div><!-- end .row -->

        <div class="row">
          <div class="input-field col m6">
            <label for="aliexpressSellerID">Aliexpress Seller ID</label>
            <input type="text" id="aliexpressSellerID" name="aliexpressSellerID" class="autocomplete">
          </div>        
        </div><!-- end .row -->

        <div class="row">
          <div class="input-field col m6">
              <label for="supplierID">Seller ID</label>
              <input type="text" id="supplierID" name="supplierID" readonly="readonly">
          </div>
        </div><!-- end .row -->

        <div class="row">
          <div class="input-field col m6">
            <label for="selectedSupplierName">Selected Supplier Name</label>
            <input type="text" id="selectedSupplierName" name="selectedSupplierName" readonly="readonly">
          </div>        
        </div><!-- end .row -->

        <div class="row">
          <div class="input-field col m6 p-1">
            <button type="submit" class="btn waves-effect waves-light" name="submitBtn" id="submitBtn" value="submit">Submit
              <i class="material-icons right">Submit</i>
            </button>
          </div>
          <div class="input-field col md6">
            <button type="close" class="btn btn-secondary btn-block" id="closeBtn" value="Close" onclick="google.script.host.close()">Close</button>
          </div>
        </div><!-- end .row -->

      </form><!-- end form -->

      <p>
        <div id="errorMsg"></div>
      </p>

      <p>
        <div id="sucessMsg"></div>
      </p>

    </div><!-- end .container -->

    <!--JavaScript at end of body for optimized loading-->
    <!-- Initialise: jQuery -->
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
    
    <!-- Initialise: LoDash-->
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>

    

    <!-- Shared javascript functions -->
    <?!= HtmlService.createHtmlOutputFromFile('sharedJavascriptFunctionsJS').getContent(); ?>
    <?!= HtmlService.createHtmlOutputFromFile('supplierIDLookupFormHTML.js').getContent(); ?> 

    <!-- Compiled and minified JavaScript -->
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
  </body>

</html>

src/supplierIDLookupFormHTML.js.html

<script>
  // Prevent forms from submitting.
  function preventFormSubmit() {
    var forms = document.querySelectorAll('form');
    for (var i = 0; i < forms.length; i++) {
      forms[i].addEventListener('submit', function(event) {
      event.preventDefault();
      });
    }
  }

  document.addEventListener('DOMContentLoaded', function() {
    window.addEventListener('load', preventFormSubmit);    
    //google.script.run.withSuccessHandler(populateSuppliers).getSuppliers();
    initialize();
    google.script.run.withSuccessHandler(populateCompanyNames).getSupplierCompanyNames();
    /*google.script.run.withSuccessHandler(populateEbayIDs).getSupplierebayIDs();
    google.script.run.withSuccessHandler(populateAmazonSellerIDs).getSupplierAmazonSellerIDs();
    google.script.run.withSuccessHandler(populateAliexpressSellerIDs).getSupplierAliexpressSellerIDs();*/
  });

  // REWRITE
  function buildAutoCompleteDataObject() {


    var customers = getDataFromHtml('customerObj_htmlservice');
    const customer = customers[Object.keys(customers)[0]];
    console.log(customer);
    //console.log(customer.customerID);
    //console.log(customer.firstName);

    // fill in the form fields using the data from the customer object.
    // loop through each entry of the customer object and match the entry with an element in the current document.
    Object.entries(customer).forEach((entry) => {
      const [key, value] = entry;
      //console.log(`${key}: ${value}`);
      //console.log(typeof `${value}`);
      
      var element = document.getElementById(`${key}`);
      if (element) {
        console.log("element (" + `${key}` + ") exists");
        document.getElementById(`${key}`).value = `${value}`;
      } else {
        console.log("Element (" + `${key}` + ") does not exist")
      }
    });
  }

  function getDataFromHtml(idData) {
    if (!idData)
        idData = "mydata_htmlservice";
    var dataEncoded = document.getElementById(idData).innerHTML;
    //console.log(dataEncoded);
    var data = JSON.parse(dataEncoded);
    return data;
  }

  //FIX THIS
  function initialize() {
    const suppliers = getDataFromHtml('suppliersObj_htmlservice');
    const supplier = suppliers[Object.keys(suppliers)[0]];
    //console.log("const suppliers: " + suppliers);
    //console.log("const supplier: " + supplier);

    _.forEach(suppliers, function(supplier) {
      _.forEach(supplier, function(value, key) {
        //console.log("lodash nested forEach():")
        //console.log(`${key}: ${value}`);
      });
      console.log("");
    });

    //console.log(suppliers[0][supplierid]);
  }

  function populateCompanyNames(companyNames){
    console.log("running: populateCompanyNames()");
    console.log(companyNames);
    var autocomplete =  document.getElementById('companyName');
    var instances = M.autocomplete.init(autocomplete, { data: companyNames });
  }

  function populateEbayIDs(ebayIDs){
    let autocomplete =  document.getElementById('ebayID');
    let instances = M.autocomplete.init(autocomplete, {data: ebayIDs});
  }

  function populateAmazonSellerIDs(amazonSellerIDss){
    let autocomplete =  document.getElementById('amazonSellerID');
    let instances = M.autocomplete.init(autocomplete, {data: amazonSellerIDs});
  }

  function populateAliexpressSellerIDs(aliexpressSellerID){
    let autocomplete =  document.getElementById('aliexpressSellerID');
    let instances = M.autocomplete.init(autocomplete, {data: aliexpressSellerIDs});
  }

    function onListFailure(error) {
      //alert(error.message);
      console.log("onListFailure() triggered. Error message was: " + error.message);
    }

    //const dropdownIDs = ["companyName", "ebayID", "amazonSellerID", "aliexpressSellerID"];


    function handleFormSubmit(formObject) {
      google.script.run.processForm(formObject);
      document.getElementById("myForm").reset();
    }

    function onClickSubmitBtnHander() {
      var supplierID = $("#supplierID").val();
      google.script.run.setCurrentCellSupplierID(supplierID);
    }

</script>

show_sidebars.js

/**
 * @function showSidebar_sellerID
 * @description TODO
 */
function showSidebar_sellerID() {
  var SIDEBAR_TITLE = 'SellerID Lookup';
  var suppliersObj = JSON.stringify(getSuppliers());
  //console.log("suppliersObj: " + suppliersObj)
  const sidebar = HtmlService.createTemplateFromFile('supplierIDLookupFormHTML')

  var htmlOutput = sidebar.evaluate();
  var strAppend = "<div id='suppliersObj_htmlservice' style='display:none;'>" + suppliersObj + "</div>";
  htmlOutput.append(strAppend);

  htmlOutput.setTitle(SIDEBAR_TITLE);  
  SpreadsheetApp.getUi().showSidebar(htmlOutput);
}

Error shown in developer console

Uncaught 
TypeError: Cannot read properties of undefined (reading 'init')
    at populateCompanyNames (userCodeAppPanel:81:36)
    at Ph (695454968-mae_html_user_bin_i18n_mae_html_user__en_gb.js:149:334)
    at 695454968-mae_html_user_bin_i18n_mae_html_user__en_gb.js:36:276
    at mf.N (695454968-mae_html_user_bin_i18n_mae_html_user__en_gb.js:102:380)
    at Ed (695454968-mae_html_user_bin_i18n_mae_html_user__en_gb.js:64:477)
    at a (695454968-mae_html_user_bin_i18n_mae_html_user__en_gb.js:62:52)

Solution

  • Autocomplete MaterializeCSS is not working

    When I saw your showing script, you are using as follows.

    var instances = M.autocomplete.init(autocomplete, {data: ###});
    

    I think that in this case, a of autocomplete is required to be A which is the capital letter. Ref So, how about the following modification? Please modify your all M.autocomplete.init to M.Autocomplete.init.

    var instances = M.Autocomplete.init(autocomplete, {data: ###});
    

    When I tested your script by using a sample value of companyNames, I confirmed the same error TypeError: Cannot read properties of undefined (reading 'init') at var instances = M.autocomplete.init(autocomplete, { data: companyNames });. And, when I modified it to var instances = M.Autocomplete.init(autocomplete, { data: companyNames });, I confirmed that the script worked.

    Note:

    Reference: