Я пытаюсь создать простую форму поиска с помощью скрипта Google Apps. Форма использует данные, полученные из электронной таблицы, для заполнения ряда полей ввода автозаполнения. Не могу понять, почему не работает автозаполнение. В поставщикеIDLookupFormHTML.html я поместил тег сценария для js-файла материализации в самый конец тега body.
Функция showSidebar_sellerID()
в show_sidebars.js добавляет простой тег div
в конец тега body. Но это не должно влиять на код Materialze JS, не так ли?
Вот мой код.
поставщикIDLookupFormHTML.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.info(customer);
//console.info(customer.customerID);
//console.info(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.info(`${key}: ${value}`);
//console.info(typeof `${value}`);
var element = document.getElementById(`${key}`);
if (element) {
console.info("element (" + `${key}` + ") exists");
document.getElementById(`${key}`).value = `${value}`;
} else {
console.info("Element (" + `${key}` + ") does not exist")
}
});
}
function getDataFromHtml(idData) {
if (!idData)
idData = "mydata_htmlservice";
var dataEncoded = document.getElementById(idData).innerHTML;
//console.info(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.info("const suppliers: " + suppliers);
//console.info("const supplier: " + supplier);
_.forEach(suppliers, function(supplier) {
_.forEach(supplier, function(value, key) {
//console.info("lodash nested forEach():")
//console.info(`${key}: ${value}`);
});
console.info("");
});
//console.info(suppliers[0][supplierid]);
}
function populateCompanyNames(companyNames){
console.info("running: populateCompanyNames()");
console.info(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.info("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.info("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);
}
Ошибка отображается в консоли разработчика
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)
Если у вас возникли проблемы с редактированием, вы можете попробовать добавить дополнительную строку между именем файла и кодом. Также может сработать добавление границ кода для форматирования кода вместо использования отступов.
Поскольку шаблон HTML включает закрывающий тег HTML, функция showSidebar_sellerID
не должна использовать HtmlService.HtmlOutput.append
для добавления кода, так как это приведет к добавлению добавленного кода после закрывающего тега HTML.
П.Д. Могут быть и другие проблемы, но в вопросе не указан «MCVE». Код из файла sharedJavascriptFunctionsJS
отсутствует. Поскольку он отсутствует, неясно, является ли это файлом .gs или .html. Если это файл .gs, другая проблема — добавить его с помощью HtmlService.createHtmlOutputFromFile
, поскольку для этого метода требуется файл .html.
Я удалил HtmlService.HtmlOutput.append
из show_sidebars.js
, но в консоли разработчика все равно была та же ошибка.
sharedJavascriptFunctionsJS
— это html-файл.
Автозаполнение MaterializeCSS не работает
Когда я увидел ваш сценарий показа, вы использовали его следующим образом.
var instances = M.autocomplete.init(autocomplete, {data: ###});
Я думаю, что в этом случае a
из autocomplete
должно быть A
, то есть заглавной буквы. Ссылка Итак, как насчет следующей модификации? Пожалуйста, измените все M.autocomplete.init
на M.Autocomplete.init
.
var instances = M.Autocomplete.init(autocomplete, {data: ###});
Когда я протестировал ваш скрипт, используя образец значения companyNames
, я подтвердил ту же ошибку TypeError: Cannot read properties of undefined (reading 'init')
в var instances = M.autocomplete.init(autocomplete, { data: companyNames });
. И когда я изменил его на var instances = M.Autocomplete.init(autocomplete, { data: companyNames });
, я подтвердил, что скрипт работает.
TypeError: Cannot read properties of undefined (reading 'init')
. Эта модификация предполагает, что другие части вашего скрипта работают нормально. Пожалуйста, будьте осторожны с этим.data
для M.Autocomplete.init(autocomplete, {data: ###})
. Итак, если ваше значение data
недействительно, измените его.Большое спасибо! Я знал, что это было что-то простое, чего мне не хватало.
@dfear Спасибо за ответ и тестирование. Я рад, что ваша проблема была решена. Спасибо и вам.
Код
sharedJavascriptFunctionsJS
отсутствует. Обязательно включите минимально воспроизводимый пример (удалите все, что не требуется для воспроизведения проблемы, но обязательно включите все необходимое).