动态 JS/HTML 元素仅在 GAS 中出现乱序? [关闭]
Posted
技术标签:
【中文标题】动态 JS/HTML 元素仅在 GAS 中出现乱序? [关闭]【英文标题】:Dynamic JS/HTML elements appear out of order only in GAS? [closed] 【发布时间】: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 【参考方案1】:当我看到您的脚本时,我认为您的问题的原因是由于数据是 JSON 对象。当看到关于 JSON 的文档时,它说如下。 Ref
在 JSON 中,它们采用以下形式:
对象是一组无序的名称/值对。一个对象以左大括号开始,以右大括号结束。每个名称后跟:冒号,名称/值对由逗号分隔。
而且,在您的脚本中,这些值是使用var fields = Object.keys(inputObj)
从 JSON 对象中检索的。为了使用您的脚本确认这一点,当 console.log(Object.keys(inputObj))
放在 Javascript 端的 function addElements(inputObj)
行之后和 Google Apps 脚本端的 return inputObj;
行之前,每个日志显示如下。
对于 Javascript 端,它是 ["fourth_field", "seventh_field", "second_field", "sixth_field", "third_field", "fifth_field", "first_fild"]
。
对于 Google Apps 脚本方面,它是 ["first_fild","second_field","third_field","fourth_field","fifth_field","sixth_field","seventh_field"]
。
发现 Javascript 端和 Google Apps 脚本端的键顺序不同。我认为这可能是您的问题的原因。
如果要使用["first_fild","second_field","third_field","fourth_field","fifth_field","sixth_field","seventh_field"]
的顺序,下面的修改如何?
修改脚本一:
在此模式中,键按顺序设置为数组。
Google Apps 脚本方面:
发件人:
return inputObj;
收件人:
return [inputObj, ["first_fild","second_field","third_field","fourth_field","fifth_field","sixth_field","seventh_field"]];
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);
收件人:
function addElements([inputObj, fields])
// Section
section = document.getElementById("input_parent");
div = document.createElement("div");
div.setAttribute("id", "input_child");
section.appendChild(div);
// var fields = Object.keys(inputObj);
修改脚本2:
在此模式中,键按顺序设置为Object.keys(inputObj)
。这样,可以在 Google Apps 脚本端和 Javascript 端之间使用相同的顺序。
Google Apps 脚本方面:
发件人:
return inputObj;
收件人:
return [inputObj, Object.keys(inputObj)];
本模式中,Javascript端的修改与模式1相同。
【讨论】:
谢谢。模式 2 工作。您查看了 GAS 端和 JavaScript 端的输出。你提到的 JavaScript 端是指 HTML 文件中的 JS 吗?如果是这样,您是如何通过 GAS 从 JS 端访问输出的? @user8121557 感谢您的回复。我很高兴你的问题得到了解决。关于Does the JavaScript-side that you mention refer to the JS in the HTML file?
的附加问题1,是的。关于If so, how did you access the output from the JS-side via GAS?
,我不得不为我糟糕的英语水平道歉。不幸的是,我无法理解您的第二个附加问题。可以问一下具体情况吗?以上是关于动态 JS/HTML 元素仅在 GAS 中出现乱序? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
仅在特定 div 中使用 javascript 更改部分链接
带头结点且递增有序的单链表AB(AB中元素个数分别为mn)分别存储了一个集合。设计算法,求AB的差集 (仅在A中出现不在B中出现),并存在A中,要求保持递增有序性