Javascript Google应用程序脚本中的变量存在问题

Javascript Google应用程序脚本中的变量存在问题,javascript,forms,google-apps-script,google-sheets-api,Javascript,Forms,Google Apps Script,Google Sheets Api,我是应用程序脚本的初学者。我试图遵循一个教程(你可以在这里找到:) 我在尝试在前端HTML中的函数之间传递变量时遇到了问题。这个项目的目标是创建一个可搜索的框,当用户在框中键入内容时进行搜索。你可以在我之前提到的视频中获得更多信息。所以,我关心的是为什么,请(我希望有人知道这个答案)我得到了一个错误,无法读取null的filter属性(应该是数据变量),并且没有定义dataReturned?我已经放置了一些console.log的语句,您可以忽略这些。有人知道发生了什么吗?这些变量(数据和返回的

我是应用程序脚本的初学者。我试图遵循一个教程(你可以在这里找到:)

我在尝试在前端HTML中的函数之间传递变量时遇到了问题。这个项目的目标是创建一个可搜索的框,当用户在框中键入内容时进行搜索。你可以在我之前提到的视频中获得更多信息。所以,我关心的是为什么,请(我希望有人知道这个答案)我得到了一个错误,无法读取null的filter属性(应该是数据变量),并且没有定义dataReturned?我已经放置了一些console.log的语句,您可以忽略这些。有人知道发生了什么吗?这些变量(数据和返回的数据)对于使用可搜索框至关重要。任何帮助都将不胜感激

错误:

未捕获的TypeError:无法读取null的属性“contains”
在checkForVideo(inject.js:465)
在inject.js:501
在NodeList.forEach()
在inject.js:499
在Array.forEach()
在requestIdleCallback.timeout时(inject.js:492)

未捕获引用错误:未定义返回的数据
在搜索时(userCodeAppPanel:48)
位于htmldevelment.inputEventHandler(userCodeAppPanel:88)

我的代码:

main.html

    <!doctype html>
    <html lang="en">
      <head>
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    
        <style>
                .nav-link {
                    cursor: pointer;
                    }
        </style>
    
      </head>
    
    <body>
        <!-- Aqui ele adiciona um container-->
        <div class="container">
            
        <!-- E aqui uma div com id que ele chama de app -->
            <div id="app">
                <!-- Aqui vem a parte de navegação da página
        Ele também trocou todas as flags a por divs, pois
        ele não queria links na navegação-->
    
                <ul class="nav nav-tabs">
                    <li class="nav-item">
                        <div class="nav-link " id="home-link">Home</div>
                    </li>
                    <li class="nav-item">
                        <div class="nav-link" id="search-link">Search</div>
                    </li>
                    <li class="nav-item">
                        <div class="nav-link" id="add-customer-link">Add Customer</div>
                    </li>
                </ul>
            </div>
        </div>
        <!-- Optional JavaScript; choose one of the two! -->
    
        <!-- Optional JavaScript -->
        <!-- jQuery first, then Popper.js, then Bootstrap JS -->
        <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    
        <script>
        
    var data = 1;
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
      
      function loadView(options){
       var id = typeof options.id === "undefined" ? "app" : options.id
       var cb = typeof options.callback === "undefined" ? function(){} : options.callback;
       google.script.run.withSuccessHandler(function(html){
       document.getElementById("app").innerHTML = html;
       typeof options.params === "undefined" ? cb() : cb(options.params);
        })[options.func](); // Aqui os colchetes representam uma propriedade.
        }
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
    
      function loadSearchView(){
        
        loadView({func:"loadSearchView", callback: setDataforSearch})//, params:{title:""}});
    }
    
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
      
      function loadAddCustomerView(){
      
        loadView({func:"loadAddCustomerView", callback: func2, req:{title:"Teste"}});
      
    }
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
    
      function loadEditCustomerView(){
      
      loadView({func:"loadAddCustomerView"})
      
      }
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
     var data= 1; // Fazendo a variável disponível globalmente
    
     function setDataforSearch(){
        
        google.script.run.withSuccessHandler(function(dataReturned){
           var data = dataReturned.slice()
           console.log(data, dataReturned)}).getDataForSearch()
           console.log(data,dataReturned); // The slice makes a copy of the array.
                                             }
    /*-----------------------------------------------------------------------------------------------------------------------------*/
       
        function search(data){
        console.log(data, dataReturned)
        var searchInput = document.getElementById("searchInput").value.toString().toLowerCase().trim();
        var searchWords = searchInput.split(/\s+/);
        var searchColumns = [1,2];
        //and or
        
        var resultsArray = searchInput === "" ? [] : data.filter(function(r){
        return searchWords.every(function(word){
        return searchColumns.some(function(colIndex){
        return r[colIndex].toString().toLowerCase().indexOf(word) !== -1
            })
          })
        })
        
        var searchResultsBox = document.getElementById("searchResults");
        var templateBox = document.getElementById("rowTemplate");
        var template = templateBox.content;
        searchResultsBox.innerHTML = "";
        resultsArray.forEach(function(r){
        
         var tr = template.clodeNode(true);
         var custIDcolumn = tr.querySelector(".custID");
         var firstNameColumn = tr.querySelector(".firstName");
         var lastNameColumn = tr.querySelector(".lastName");
          
          custIDcolumn.textContent = r[0];
          firstNameColumn.textContent = r[1];
          lastNameColumn.textContent = r[2];
          searchResultsBox.appendChild(tr);
        })
        }
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
      
       document.getElementById("search-link").addEventListener("click", loadSearchView);
       document.getElementById("add-customer-link").addEventListener("click", loadAddCustomerView);
       document.getElementById("home-link").addEventListener("click", loadAddCustomerView);
       
       function inputEventHandler(e){
        
        if(e.target.matches("#searchInput")){
              search();
          }
        }
        
       document.getElementById("app").addEventListener("input", inputEventHandler);
       
       
        </script>
    
    </body>
    
    </html>
function loadMainForm() {
      const htmlServ = HtmlService.createTemplateFromFile('main');
      const html = htmlServ.evaluate();
      // Caso queira mudar o tamanho do formulário html.setwidth html.setheight
      const ui = SpreadsheetApp.getUi(); 
      ui.showModalDialog(html, "Edit Customer Data");
}
    
function createMenu_(){ // Essa função vai adicionar o menu lá na barra de menus
                            // O UNDERSCORE trasnforma essa função em privada
    
      const ui = SpreadsheetApp.getUi();
      const menu = ui.createMenu("Custom Menu");
      menu.addItem("Open Form", "loadMainForm"); // Aqui vem a função que cria o menu e o formulário em html em si
      menu.addToUi();
}
    
function onOpen(){ // Essa função vai ser chamada toda vez que abrirmos a planilha pra que haja a criação do menu
    
      createMenu_();
    
}
function loadPartialHTML_(partial) { // partial vai ser dinâmico, cada hora sendo uma página
      const htmlServ = HtmlService.createTemplateFromFile(partial);
      return htmlServ.evaluate().getContent(); // Aqui o html é só texto pra ser renderizado
}
    
function loadSearchView() {
    
      return loadPartialHTML_("search");
    
}
    
function loadAddCustomerView() {
    
      return loadPartialHTML_("addcustomer");
    
}
    
function loadEditCustomerView() {
    
      return loadPartialHTML_("editcustomer");
    
}
    
loadPartials.gs

    <!doctype html>
    <html lang="en">
      <head>
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    
        <!-- Bootstrap CSS -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    
        <style>
                .nav-link {
                    cursor: pointer;
                    }
        </style>
    
      </head>
    
    <body>
        <!-- Aqui ele adiciona um container-->
        <div class="container">
            
        <!-- E aqui uma div com id que ele chama de app -->
            <div id="app">
                <!-- Aqui vem a parte de navegação da página
        Ele também trocou todas as flags a por divs, pois
        ele não queria links na navegação-->
    
                <ul class="nav nav-tabs">
                    <li class="nav-item">
                        <div class="nav-link " id="home-link">Home</div>
                    </li>
                    <li class="nav-item">
                        <div class="nav-link" id="search-link">Search</div>
                    </li>
                    <li class="nav-item">
                        <div class="nav-link" id="add-customer-link">Add Customer</div>
                    </li>
                </ul>
            </div>
        </div>
        <!-- Optional JavaScript; choose one of the two! -->
    
        <!-- Optional JavaScript -->
        <!-- jQuery first, then Popper.js, then Bootstrap JS -->
        <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    
        <script>
        
    var data = 1;
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
      
      function loadView(options){
       var id = typeof options.id === "undefined" ? "app" : options.id
       var cb = typeof options.callback === "undefined" ? function(){} : options.callback;
       google.script.run.withSuccessHandler(function(html){
       document.getElementById("app").innerHTML = html;
       typeof options.params === "undefined" ? cb() : cb(options.params);
        })[options.func](); // Aqui os colchetes representam uma propriedade.
        }
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
    
      function loadSearchView(){
        
        loadView({func:"loadSearchView", callback: setDataforSearch})//, params:{title:""}});
    }
    
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
      
      function loadAddCustomerView(){
      
        loadView({func:"loadAddCustomerView", callback: func2, req:{title:"Teste"}});
      
    }
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
    
      function loadEditCustomerView(){
      
      loadView({func:"loadAddCustomerView"})
      
      }
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
     var data= 1; // Fazendo a variável disponível globalmente
    
     function setDataforSearch(){
        
        google.script.run.withSuccessHandler(function(dataReturned){
           var data = dataReturned.slice()
           console.log(data, dataReturned)}).getDataForSearch()
           console.log(data,dataReturned); // The slice makes a copy of the array.
                                             }
    /*-----------------------------------------------------------------------------------------------------------------------------*/
       
        function search(data){
        console.log(data, dataReturned)
        var searchInput = document.getElementById("searchInput").value.toString().toLowerCase().trim();
        var searchWords = searchInput.split(/\s+/);
        var searchColumns = [1,2];
        //and or
        
        var resultsArray = searchInput === "" ? [] : data.filter(function(r){
        return searchWords.every(function(word){
        return searchColumns.some(function(colIndex){
        return r[colIndex].toString().toLowerCase().indexOf(word) !== -1
            })
          })
        })
        
        var searchResultsBox = document.getElementById("searchResults");
        var templateBox = document.getElementById("rowTemplate");
        var template = templateBox.content;
        searchResultsBox.innerHTML = "";
        resultsArray.forEach(function(r){
        
         var tr = template.clodeNode(true);
         var custIDcolumn = tr.querySelector(".custID");
         var firstNameColumn = tr.querySelector(".firstName");
         var lastNameColumn = tr.querySelector(".lastName");
          
          custIDcolumn.textContent = r[0];
          firstNameColumn.textContent = r[1];
          lastNameColumn.textContent = r[2];
          searchResultsBox.appendChild(tr);
        })
        }
    /*-----------------------------------------------------------------------------------------------------------------------------*/ 
      
       document.getElementById("search-link").addEventListener("click", loadSearchView);
       document.getElementById("add-customer-link").addEventListener("click", loadAddCustomerView);
       document.getElementById("home-link").addEventListener("click", loadAddCustomerView);
       
       function inputEventHandler(e){
        
        if(e.target.matches("#searchInput")){
              search();
          }
        }
        
       document.getElementById("app").addEventListener("input", inputEventHandler);
       
       
        </script>
    
    </body>
    
    </html>
function loadMainForm() {
      const htmlServ = HtmlService.createTemplateFromFile('main');
      const html = htmlServ.evaluate();
      // Caso queira mudar o tamanho do formulário html.setwidth html.setheight
      const ui = SpreadsheetApp.getUi(); 
      ui.showModalDialog(html, "Edit Customer Data");
}
    
function createMenu_(){ // Essa função vai adicionar o menu lá na barra de menus
                            // O UNDERSCORE trasnforma essa função em privada
    
      const ui = SpreadsheetApp.getUi();
      const menu = ui.createMenu("Custom Menu");
      menu.addItem("Open Form", "loadMainForm"); // Aqui vem a função que cria o menu e o formulário em html em si
      menu.addToUi();
}
    
function onOpen(){ // Essa função vai ser chamada toda vez que abrirmos a planilha pra que haja a criação do menu
    
      createMenu_();
    
}
function loadPartialHTML_(partial) { // partial vai ser dinâmico, cada hora sendo uma página
      const htmlServ = HtmlService.createTemplateFromFile(partial);
      return htmlServ.evaluate().getContent(); // Aqui o html é só texto pra ser renderizado
}
    
function loadSearchView() {
    
      return loadPartialHTML_("search");
    
}
    
function loadAddCustomerView() {
    
      return loadPartialHTML_("addcustomer");
    
}
    
function loadEditCustomerView() {
    
      return loadPartialHTML_("editcustomer");
    
}
    
服务器端功能:

function getDataForSearch() {
        const ss = SpreadsheetApp.getActiveSpreadsheet();
        const ws = ss.getSheetByName("Customers");
        return ws.getRange(2, 1, ws.getLastRow()-1, 3).getValues();
}

这是项目的主要部分,伙计们。如果你们中有人理解我为什么会出现这样的错误,请帮助我构建这个。我真的需要这个应用程序工作。

html注释是这样附上的
而不是这个
/**/
我会把它们放在一个窗口中。onload:document.getElementById(“搜索链接”).addEventListener(“单击”,loadSearchView);document.getElementById(“添加客户链接”).addEventListener(“单击”,loadAddCustomerView);document.getElementById(“主页链接”).addEventListener(“单击”,loadAddCustomerView);与此相同:document.getElementById(“app”).addEventListener(“输入”,inputEventHandler);您已经申报了两次数据顺便说一句,非常感谢您的努力和时间!