【问题标题】:How to Add 'Data List' in Google Sheet Apps Script that Populates Data from from Google Sheet with Bootstrap and HTML5如何在使用 Bootstrap 和 HTML5 填充来自 Google Sheet 的数据的 Google Sheet Apps 脚本中添加“数据列表”
【发布时间】:2021-03-04 11:41:49
【问题描述】:

首先抱歉,如果这是一个愚蠢的问题,因为我是编码和编程的新手。

我正在尝试使用 Google Apps 脚本为我的公司创建一个 CRM Webapp,它将所有数据存储在 Google Sheet 中。工作仍在进行中。

这个 CRM Web 应用程序基本上有一个主页选项卡(用于搜索和编辑数据)、销售选项卡(用于输入销售条目)、购买选项卡(用于输入购买条目)和联系选项卡(用于添加联系方式)。

这个想法是,用户将首先在“联系”选项卡中添加新客户/供应商的联系方式,这些数据将存储在 Google 表格中。

现在要进行销售或购买条目,用户现在必须首先在相应的选项卡中选择已输入的联系人(仅显示姓名、电话号码和电子邮件 ID)。

为此,我正在尝试从 Bootstrap 添加一个数据列表,这将帮助用户搜索和选择已存储的联系人详细信息,并且需要根据所选姓名/电子邮件/电话自动填写相关的联系人字段。

我厌倦了很多方法并参考了几个帖子,但我无法从 Google 表格中填充搜索数据。我尝试使用下拉逻辑,但即使这样也不起作用。

以下是我的代码。我只粘贴看起来与你们相关的部分,因为整个事情非常杂乱无章。任何帮助将不胜感激。

加载表单.gs:

function loadForm() {
  
const htmlServ = HtmlService.createTemplateFromFile("uform");
const html = htmlServ.evaluate();
html.setWidth(850).setHeight(600);
const ui = SpreadsheetApp.getUi();

ui.showModalDialog(html, "VKSPCPL CRM");

}

function createMenu_(){

const ui = SpreadsheetApp.getUi();
const menu = ui.createMenu("CRM");
menu.addItem("Open APP", "loadForm");
menu.addToUi(); 

}

function onOpen(){

createMenu_();

}

函数.gs:

//Sales Functions---------------------------

function salesEntry(rowDataSales) {

const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Sales Contact Details");
const currentDate = new Date();

const uniqueIDs = ws.getRange(2, 1, ws.getLastRow()-1, 1).getValues();
var maxNum = 0;
uniqueIDs.forEach(r => {
  maxNum = r[0] > maxNum ? r[0] : maxNum
});
var caseNo = maxNum + 1;

ws.appendRow([
  caseNo,
  rowDataSales.inputSalesCxName,
  "Sales",
  rowDataSales.inputSalesCaseOwner,
  currentDate,
  rowDataSales.inputSalesCoName,
  rowDataSales.inputSalesEmail,
  rowDataSales.inputSalesPhone,
  rowDataSales.inputSalesGST,
  rowDataSales.inputSalesCoAdd,
  rowDataSales.inputSalesState]);

  return true;
 
}

function getSalesCaseOwnerDropdown(){

const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("CaseOwners");
return ws.getRange(2, 1, ws.getLastRow()-1, 1).getValues();

}

function salesStateList(){

const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("States");
return ws.getRange(2, 1, ws.getLastRow()-1, 1).getValues();

}

function salesContactName(){

const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Contact Details");
return ws.getRange(2, 1, ws.getLastRow()-1, 1).getValues();

}

    
//-------------------------------------------------------------------------------------------
//Contact Functions--------------------------------------------------------------------------

function getContactDropdown(){

const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Customer Type");
return ws.getRange(2, 1, ws.getLastRow()-1, 2).getValues();

}

function contactEntry(rowDataContact) {

const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Contact Details");
const currentDate = new Date();

ws.appendRow([
  rowDataContact.inputContactName,
  rowDataContact.inputContactCoName,
  rowDataContact.inputContactPhone,
  rowDataContact.inputContactEmail,
  rowDataContact.inputContactGST,
  rowDataContact.inputContactCoAdd,
  rowDataContact.inputContactState,
  rowDataContact.inputContactCategory,
  rowDataContact.inputContactType,
  currentDate]);

  return true;
 
}

function contactStateList(){

const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("States");
return ws.getRange(2, 1, ws.getLastRow()-1, 1).getValues();

}

uform.html:

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">

  </head>
  <body>
  
    <div class="container">
      <ul class="nav nav-tabs" id="myTab" role="tablist">
      <li class="nav-item" role="presentation">
    <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#home" type="button" role="tab" aria-controls="home" aria-selected="true">Home</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="sales-tab" data-bs-toggle="tab" data-bs-target="#sales" type="button" role="tab" aria-controls="sales" aria-selected="false">Sales</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="purchase-tab" data-bs-toggle="tab" data-bs-target="#purchase" type="button" role="tab" aria-controls="purchase" aria-selected="false">Purchase</button>
  </li>
   <li class="nav-item" role="presentation">
    <button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#contact" type="button" role="tab" aria-controls="contact" aria-selected="false">Contact Details</button>
  </li>
</ul>
<div class="tab-content" id="myTabContent">
  <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">1</div>
  <div class="tab-pane fade" id="sales" role="tabpanel" aria-labelledby="sales-tab">
    
    <br><h3 class="display-6">New Sales Case</h3>

    <div class="col-md-4">
      <select class="form-select form-select-sm" aria-label=".form-select-sm example" id="inputSales-CaseOwner">
   
    </select>
    </div>

    <br><h5>Contact Details</h5>

    <form class="row g-3">
       <div class="col-md-4">
      <label for="exampleDataList" class="form-label">Datalist example</label>
      <input class="form-control" list="datalistOptions" id="exampleDataList" placeholder="Type to search...">
      <datalist id="inputSales-CxName">
    
      </datalist>

    ...
    ...
    ...
    
    <script>
    //JS Script Here
    </script>
    </body>
    </html>

如果你们需要更多脚本或详细信息,请告诉我。任何帮助将不胜感激。提前非常感谢!

【问题讨论】:

  • 很遗憾,我无法理解Loadform.gsFunctions.gsuform.html 之间的关系。所以我无法理解I tired a lot of methods and referred several posts, but I am not able to populate the Search data from within Google Sheet. I tried using the Dropdown Logic, but even that did not work.。我为此道歉。我可以问一下您当前问题的详细信息和您的目标吗?
  • @Tanaike 嗨,已创建 loadform.gs 以将用户窗体部署为模态窗口。 Functions.gs 包含在后端运行的所有函数,uform.gs 包含所有前端 html 脚本。我的目标是在“销售标签”中有一个可搜索的下拉菜单,这将允许任何用户搜索联系人(通过“联系人标签”在“联系人详细信息”表中捕获)。记录的联系人将有几个参数:姓名、号码、电子邮件 ID 等(这些都记录在单独的列中)。(1/n)
  • @Tanaike 我希望用户可以通过输入上述任何参数从销售选项卡中的第一个可搜索下拉列表中搜索所需的联系人,但只有“联系人姓名”应该出现在用户表单中的所述字段。基于此选择,其余字段(电话、电子邮件、公司名称)应自动填充到单独的禁用下拉列表中。为之前的混乱道歉。我希望我能够解释我的问题。 (2/2)
  • 感谢您的回复。当我看到你的Functions.gs时,似乎Functions.gs的功能在Loadform.gsuform.html上没有使用。 uform.html 是否独立于其他文件?如果我误解了您的问题,我深表歉意。
  • 嗨@Tanaike,functions.gs 与uform.gs 相关联。 Loadform.gs 是独立的。如果您愿意,我可以将整个代码发给您以便更好地理解。我没有在这里发布它,因为它非常杂乱无章,看起来很乱

标签: javascript html google-apps-script bootstrap-modal datalist


【解决方案1】:

根据您的问题,我了解到您希望执行搜索,如果它与您已经存储在工作表中的名称之一匹配,则应该使用与该名称对应的信息填充 select HTML 元素选项,并且应该被禁用。

为了做到这一点,我首先遵循了 Apps 脚本指南中的 this detailed and well explained example,了解如何处理表单并将表单输入信息传递到您的 code.gs 文件。然后,一旦我根据使用getValues 获得的电子表格列A 检查输入数据,我就会在与输入名称对应的选定行中返回匹配数据。最后我只是简单地使用innerHtmlgetElementById来修改选择字段。

我构建了一个简单而抽象的示例,说明如何实现您的目标,以便其他有类似疑问的用户可以从中学习。请调整您的代码以包含此示例。下面我插入了工作表数据结构和网络应用程序工作方式的图像:

代码中有不言自明的 cmets,但如果您有任何疑问,请随时询问他们:

HTML 文件、代码文件

function doGet(e) {
  var template = HtmlService.createTemplateFromFile('Index');

  return template.evaluate().setTitle('Web App Window Title');
}

// name is an object like this {name : "your inputed name"}
function getData(name) {

// Get the sheet where you have all your data
  var sheet = SpreadsheetApp.openById('1Ifqk1LukwzjeZHc7DulMmoZPl34zbHNnLIzFanFAsqI').getSheetByName('Sheet1');
  
  // Get a list of all your stored names. As getValues returns a 2D array, if 
  // you use flat() it will convert it into a 1D array which is of easier manipullation
  var names = sheet.getRange(2,1,sheet.getLastRow(),1).getValues().flat();
  
  // variable to store matching name data
  var populateElements;
  
  // if the array of names has the name entered in the input
  if(names.includes(name.name)){
  
    // get the index of the matching name in the names array
    var index = names.indexOf(name.name);
    
    // get an array of corresponding values of the name
    // i.e age and field in this example
    populateElements = sheet.getRange(index+2,2,1,2).getValues().flat();
    // return the array of matching fields for that name
    return populateElements;
  }else{
    // if there was no name match just return whatever you want that is not an array
    return "popcorn"
  }

}
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <!-- STYLES -->
    <?!= HtmlService.createHtmlOutputFromFile('Stylesheet').getContent(); ?>
    <script>
      // This function is used so that the form submission 
      // does not refresh the web app
      function preventFormSubmit() {
        var forms = document.querySelectorAll('form');
        for (var i = 0; i < forms.length; i++) {
          forms[i].addEventListener('submit', function(event) {
            event.preventDefault();
          });
        }
      }
      window.addEventListener('load', preventFormSubmit);

      // Function that gets the data returned getData if everything worked fine
      function onSuccess(data) {
      
      // data is the array of the elements to be populated.
      // In this example [age, field]
      
      // Select the HTML select elements
        var selectAge = document.getElementById('age');
        var selectField = document.getElementById('field');
      // create the variables that will store the options
        var optionAge;
        var optionField;
        // if data is an array and thus the name searched was successful and 
        // there were matches
        if(data.length){
        // create an option HTML element for each element in the array
          optionAge = "<option value='" + data[0] + " disabled'>" + data[0] + "</option>";
          
          // and set it to the corresponding select element
          selectAge.innerHTML = optionAge;

          optionField = "<option value='" + data[1] + " disabled'>" + data[1] + "</option>";
          selectField.innerHTML = optionField;

        }

      }

      // This function will run when the form is submitted
      // formObject is that data submitted. In this case this is equals to {name:name}
      function handleFormSubmit(formObject) {
      
      // set to run getData passing the inputed name and if successful run the function
      // ablove onSuccess
        google.script.run.withSuccessHandler(onSuccess).getData(formObject);
      }
    </script>
  </head>
  <body>
    <h1>
      Select Name
    </h1>

    <!-- On this form submission this will call the function handleFormSubmit -->
    <!-- and it will pass the input value -->
    <form id="myForm" onsubmit="handleFormSubmit(this)">
      <input name="name" type="text" />
      <input type="submit" value="Submit" />
    </form>
    
    <!-- The select inputs that will be modified on the name search -->
    <select name="age" id="age">
      <option value="Selection 1">Selection 1</option>
      <option value="Selection 2">Selection 2</option>
    </select>

    <select name="field" id="field">
      <option value="Selection 1">Selection 1</option>
      <option value="Selection 2">Selection 2</option>
    </select>

  </body>
</html>

【讨论】:

  • 嗨,非常感谢您的回复。我大部分时间都在工作。我想知道是否有一种方法可以添加可搜索的下拉列表而不是输入字段。我在引导程序 4 上找不到这样做的方法。这是我的实际问题:stackoverflow.com/questions/66490112/…
  • 很高兴它解决了您的问题! :D HTML 或 Bootstrap 上没有可搜索的 select 元素,但您可以使用 [datalist](w3schools.com/tags/tag_datalist.asp) 代替。
  • 嗨,我确实设法使用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多