Javascript Google应用程序脚本中的变量存在问题
我是应用程序脚本的初学者。我试图遵循一个教程(你可以在这里找到:) 我在尝试在前端HTML中的函数之间传递变量时遇到了问题。这个项目的目标是创建一个可搜索的框,当用户在框中键入内容时进行搜索。你可以在我之前提到的视频中获得更多信息。所以,我关心的是为什么,请(我希望有人知道这个答案)我得到了一个错误,无法读取null的filter属性(应该是数据变量),并且没有定义dataReturned?我已经放置了一些console.log的语句,您可以忽略这些。有人知道发生了什么吗?这些变量(数据和返回的数据)对于使用可搜索框至关重要。任何帮助都将不胜感激 错误: 未捕获的TypeError:无法读取null的属性“contains”Javascript Google应用程序脚本中的变量存在问题,javascript,forms,google-apps-script,google-sheets-api,Javascript,Forms,Google Apps Script,Google Sheets Api,我是应用程序脚本的初学者。我试图遵循一个教程(你可以在这里找到:) 我在尝试在前端HTML中的函数之间传递变量时遇到了问题。这个项目的目标是创建一个可搜索的框,当用户在框中键入内容时进行搜索。你可以在我之前提到的视频中获得更多信息。所以,我关心的是为什么,请(我希望有人知道这个答案)我得到了一个错误,无法读取null的filter属性(应该是数据变量),并且没有定义dataReturned?我已经放置了一些console.log的语句,您可以忽略这些。有人知道发生了什么吗?这些变量(数据和返回的
在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);您已经申报了两次数据顺便说一句,非常感谢您的努力和时间!