【发布时间】:2022-01-23 21:11:00
【问题描述】:
我有一个从 Google Apps 脚本生成的动态 HTML 表单。我希望元素以与它们在输入对象中出现的顺序相同的顺序出现,这与我附加元素的顺序相同。但这些元素实际上以意想不到的顺序出现。
我关注this other post 试图解决这个问题,但是当我在 GAS 中运行我的代码时,这些元素仍然出现乱序。问题是,当我运行my code in jsfiddle 时,它按预期工作,即元素以与它们在输入对象中相同的顺序出现。 GAS 中的元素只是没有按预期排序。
为什么元素在 GAS 中出现乱序,而在 jsfiddle 中却出现有序?如何在 GAS 中使用 vanilla JS 解决这个问题?
jsfiddle代码副本:
HTML
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<div id='input_parent'></div>
</body>
<br><input type="button" value="Submit" onClick="test()">
</form>
JS
inputObj = {"first field":{"required":true,"dataType":"select","options":["first opt","second opt"]},"second field":{"required":true,"dataType":"text","options":"none"}}
// Section
section = document.getElementById("input_parent");
div = document.createElement("div");
div.setAttribute("id", "input_child");
section.appendChild(div);
var fields = Object.keys(inputObj);
Array.from(fields).forEach((arg) => {
// Label
section = document.getElementById("input_parent");
label = document.createElement("label");
label.setAttribute("id", "label_"+arg);
label.setAttribute("for", arg);
label_txt = document.createTextNode(arg+":");
label.appendChild(label_txt);
section.appendChild(label);
if (inputObj[arg].dataType == "select") {
// Create select element
section = document.getElementById("input_parent");
const select_element = document.createElement("select");
select_element.setAttribute("id", "select_"+arg);
section.appendChild(select_element);
var options = inputObj[arg].options
for(let o = 0; o < options.length; o++)
{
var element = document.getElementById("select_"+arg);
const option = document.createElement("option");
var text = document.createTextNode(arg+":");
option.textContent = options[o];
option.setAttribute("value", options[o]);
element.appendChild(option);
};
} else {
section = document.getElementById("input_parent");
input_field = document.createElement("input");
input_field.setAttribute("id", "input_"+arg);
input_field.setAttribute("type", inputObj[arg].dataType);
section.appendChild(input_field);
}
});
回复@Nikko J 的其他信息。以下代码应重现下图中的结果。
dynamHtmlTbrlsht.html 渲染表单。
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<div id='input_parent'></div>
</body>
<br><input type="button" value="Submit" onClick="test()">
</html>
<script type='text/javascript'>
window.onload = function(){
google.script.run.withSuccessHandler(addElements).getElementInfo();
}
</script>
<script type='text/javascript'>
function addElements(inputObj) {
// Section
section = document.getElementById("input_parent");
div = document.createElement("div");
div.setAttribute("id", "input_child");
section.appendChild(div);
var fields = Object.keys(inputObj);
Array.from(fields).forEach((arg) => {
// Label
section = document.getElementById("input_parent");
label = document.createElement("label");
label.setAttribute("id", "label_"+arg);
label.setAttribute("for", arg);
label_txt = document.createTextNode(arg+":");
label.appendChild(label_txt);
section.appendChild(label);
if (inputObj[arg].dataType == "select") {
// Create select element
section = document.getElementById("input_parent");
const select_element = document.createElement("select");
select_element.setAttribute("id", "select_"+arg);
section.appendChild(select_element);
var options = inputObj[arg].options
for(let o = 0; o < options.length; o++)
{
var element = document.getElementById("select_"+arg);
const option = document.createElement("option");
var text = document.createTextNode(arg+":");
option.textContent = options[o];
option.setAttribute("value", options[o]);
element.appendChild(option);
};
} else {
section = document.getElementById("input_parent");
input_field = document.createElement("input");
input_field.setAttribute("id", "input_"+arg);
input_field.setAttribute("type", inputObj[arg].dataType);
section.appendChild(input_field);
}
});
}
</script>
trblsht.gs 创建输入对象。 (请注意,这是为了解决手头的问题而进行了简化。实际上,inputObj 是通过运行一些动态创建对象并从外部源获取选项的函数来生成的。)
function getElementInfo() {
var inputObj = {"first_fild":{"required":true,"dataType":"select","options":["option 1","option 2","option 3","option 4"]},"second_field":{"required":true,"dataType":"text","options":"none"},"third_field":{"required":true,"dataType":"text","options":"none"},"fourth_field":{"required":true,"dataType":"text","options":"none"},"fifth_field":{"required":false,"dataType":"select","options":["option 1","option 2","option 3","option 4","option 5","option 6","option 7","option 8","option 9","option10"]},"sixth_field":{"required":false,"options":"none"},"seventh_field":{"required":false,"dataType":"select","options":["option 1","option 2","option 3","option 4","option 5","option 6"]}}
Logger.log("inputObj: "+JSON.stringify(inputObj))
return inputObj;
}
为了完整起见,以下几行位于onEdit 函数中,该函数在活动单元格== "troubleshoot" 时生成表单。
function myOnEditTriggerFunc() {
// do other stuff
var currentRange = SpreadsheetApp.getActiveRange();
var currentVal =
currentRange.getValue().toString().replace(/(^\s+|\s+$)/g,"");
if (currentVal == "troubleshoot") {
openHTML("dynamHtmlTbrlsht","Troubleshoot",400)
return;
}
}
openHTML()在上述函数中引用。
function openHTML(htmlFile,htmlTitle,height) {
var html = HtmlService.createHtmlOutputFromFile(htmlFile)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setHeight(height);
SpreadsheetApp.getUi()
.showModalDialog(html, htmlTitle);
return;
};
jsfiddle显示正常的js。
我开始怀疑问题是否出在dynamHtmlTbrlsht.html 中的Array.from(fields).forEach((arg)。我故意使用Array 而不是Object,因为Array is ordered 而Object 是not always ordered(取决于ES)。也许有与V8 runtime 相关的东西影响了这一点,而我没有注意到?
【问题讨论】:
-
您是如何在应用程序脚本中对此进行测试的?您能否向我们展示您在应用程序脚本中的代码以及 GAS 与普通 JS 中输出的屏幕截图。另见minimal reproducible example
标签: javascript html google-apps-script