1

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/[email protected]/dist/jquery.min.js"></script>
    
    <!-- Initialise: LoDash-->
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/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)
2
  • The code of sharedJavascriptFunctionsJS is missing. Please ensure to include a minimal reproducible example (remove all the stuff that is not required to reproduce the problem, but ensure to include all that is required).
    – Wicket
    Commented Aug 25, 2024 at 15:27
  • 1
    If you have trouble editing, you can try adding additional line between name of the file and code. Also adding code fences ``` for formatting code instead using indentation might work.
    – Dalija Prasnikar
    Commented Aug 25, 2024 at 19:38

2 Answers 2

1

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:

  • This answer is for resolving your error TypeError: Cannot read properties of undefined (reading 'init'). This modification supposes that the other parts of your script work fine. Please be careful about this.
  • I cannot know your value of data for M.Autocomplete.init(autocomplete, {data: ###}). So, if your value of data is invalid, please modify it.

Reference:

2
  • Thank you so much! I new it was something simple, that I was missing.
    – dfear
    Commented Aug 26, 2024 at 20:13
  • @dfear Thank you for replying and testing it. I'm glad your issue was resolved. Thank you, too.
    – Tanaike
    Commented Aug 27, 2024 at 0:30
0

Since the HTML template includes a closing HTML tag, the showSidebar_sellerID function should not use HtmlService.HtmlOutput.append to append code, as this will cause the appended code to be added after the closing HTML tag.

P.D. There might be other problems, but the question doesn't include an "MCVE". The code from the file sharedJavascriptFunctionsJS is missing. Because it's missing, it is unclear if it is a .gs or a .html file. If it's a .gs file another problem is adding it using HtmlService.createHtmlOutputFromFile as this method requires a .html file.

2
  • I removed HtmlService.HtmlOutput.append from show_sidebars.js, but the dev console still had the same error.
    – dfear
    Commented Aug 25, 2024 at 21:30
  • sharedJavascriptFunctionsJS is a html file.
    – dfear
    Commented Aug 25, 2024 at 21:31

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.