如何在 Google Sheet 应用程序脚本中添加 'Data List' 从 Google Sheet 使用 Bootstrap 和 HTML5 填充数据
How to Add 'Data List' in Google Sheet Apps Script that Populates Data from from Google Sheet with Bootstrap and HTML5
首先,如果这是一个愚蠢的问题,我深表歉意,因为我是编码和编程的新手。
我正在尝试使用 Google Apps 脚本为我的公司创建一个 CRM Web 应用程序,它将其所有数据存储在 Google Sheet 中。工作仍在进行中。
此 CRM Web 应用程序基本上将有一个主页选项卡(用于搜索和编辑数据)、销售选项卡(用于输入销售条目)、采购选项卡(用于输入采购条目)和联系人选项卡(用于添加联系人详细信息)。
这个想法是用户首先在联系人选项卡中添加一个新的 Customer/Supplier 的联系人详细信息,并且此数据将存储在 Google Sheet 中。
现在要进行销售或购买条目,用户现在必须首先 select 已输入的联系人(只有姓名,Phone 号码和电子邮件 ID 将可见)各自的Tab.
为此,我试图从 Bootstrap 添加一个数据列表,这将帮助用户搜索和 select 已经存储的联系方式,并且依赖的联系字段需要根据自动填写在选定的 Name/Email/Phone.
我尝试了很多方法并参考了几篇文章,但我无法从 Google Sheet 中填充搜索数据。我尝试使用下拉逻辑,但即使那样也不起作用。
以下是我的代码。我只粘贴看起来与你们相关的部分,因为整个事情非常杂乱无章。任何帮助将不胜感激。
Loadform.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_();
}
Functions.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>
如果你们需要更多脚本或细节,请告诉我。任何帮助将不胜感激。非常感谢!
From your question I understood that you want a search to be performed that if it matches one of the names you already have stored in your sheet then the select HTML element options should get populated with the information corresponding to that name and should get disabled.
为了做到这一点,我首先按照 this detailed and well explained example from Apps Script guides on how to deal with forms and pass form input information to your code.gs
file. Then, once I checked the input data against the Spreadsheet column A
that I obtained using getValues I returned the matching data in the selected row corresponding to the inputed name. Finally I simply used innerHtml and getElementById 修改了 select 字段。
我已经构建了一个简单而抽象的示例来说明如何实现您的目标,以便其他有类似疑问的用户可以从中学习。请调整您的代码以包含此示例。下面我插入了有关 sheet 数据结构和 Web 应用程序工作方式的图像:
该代码有不言自明的注释,但如果您有任何疑问,请随时询问它们:
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>
首先,如果这是一个愚蠢的问题,我深表歉意,因为我是编码和编程的新手。
我正在尝试使用 Google Apps 脚本为我的公司创建一个 CRM Web 应用程序,它将其所有数据存储在 Google Sheet 中。工作仍在进行中。
此 CRM Web 应用程序基本上将有一个主页选项卡(用于搜索和编辑数据)、销售选项卡(用于输入销售条目)、采购选项卡(用于输入采购条目)和联系人选项卡(用于添加联系人详细信息)。
这个想法是用户首先在联系人选项卡中添加一个新的 Customer/Supplier 的联系人详细信息,并且此数据将存储在 Google Sheet 中。
现在要进行销售或购买条目,用户现在必须首先 select 已输入的联系人(只有姓名,Phone 号码和电子邮件 ID 将可见)各自的Tab.
为此,我试图从 Bootstrap 添加一个数据列表,这将帮助用户搜索和 select 已经存储的联系方式,并且依赖的联系字段需要根据自动填写在选定的 Name/Email/Phone.
我尝试了很多方法并参考了几篇文章,但我无法从 Google Sheet 中填充搜索数据。我尝试使用下拉逻辑,但即使那样也不起作用。
以下是我的代码。我只粘贴看起来与你们相关的部分,因为整个事情非常杂乱无章。任何帮助将不胜感激。
Loadform.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_();
}
Functions.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>
如果你们需要更多脚本或细节,请告诉我。任何帮助将不胜感激。非常感谢!
From your question I understood that you want a search to be performed that if it matches one of the names you already have stored in your sheet then the select HTML element options should get populated with the information corresponding to that name and should get disabled.
为了做到这一点,我首先按照 this detailed and well explained example from Apps Script guides on how to deal with forms and pass form input information to your code.gs
file. Then, once I checked the input data against the Spreadsheet column A
that I obtained using getValues I returned the matching data in the selected row corresponding to the inputed name. Finally I simply used innerHtml and getElementById 修改了 select 字段。
我已经构建了一个简单而抽象的示例来说明如何实现您的目标,以便其他有类似疑问的用户可以从中学习。请调整您的代码以包含此示例。下面我插入了有关 sheet 数据结构和 Web 应用程序工作方式的图像:
该代码有不言自明的注释,但如果您有任何疑问,请随时询问它们:
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>