skip to Main Content

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

Answers


  1. 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.

    Login or Signup to reply.
  2. 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:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search