方法UiInstance.getElementById(ID)
始终返回GenericWidget
个对象,即使ID不存在。
是否有某种方法可以找出我的应用中不存在返回的对象,或者检查UI是否包含具有给定ID的对象?
使用GUI构建器创建的UI解决方案:
function getSafeElement(app, txtID) {
var elem = app.getElementById(txtID);
var bExists = elem != null && Object.keys(elem).length < 100;
return bExists ? elem : null;
}
如果ID不存在,则返回null。我没有测试所有小部件的密钥长度边界,所以要小心并用你的GUI测试它。
编辑:此解决方案仅适用于doGet()
函数。它在服务器处理程序中不起作用,因此在这种情况下将它与@ corey-g answer结合使用。
答案 0 :(得分:4)
这只会在您创建窗口小部件的同一执行中起作用,而不会在您检索窗口小部件的后续事件处理程序中起作用,因为在这种情况下,无论是否存在,所有内容都是GenericWidget。
您可以亲眼看到解决方案失败:
function doGet() {
var app = UiApp.createApplication();
app.add(app.createButton().setId("control").addClickHandler(
app.createServerHandler("clicked")));
app.add(app.createLabel(exists(app)));
return app;
}
function clicked() {
var app = UiApp.getActiveApplication();
app.add(app.createLabel(exists(app)));
return app;
}
function exists(app) {
var control = app.getElementById("control");
return control != null && Object.keys(control).length < 100;
}
应用程序将首先打印“true”,但在点击处理程序中,它将为同一个小部件打印“false”。
这是设计上的; GenericWidget是对浏览器中的窗口小部件进行排序的“指针”。我们不会跟踪您创建的小部件,以减少浏览器和脚本之间的数据传输和延迟(否则我们必须发送每个事件处理程序上存在的小部件的长列表)。您应该跟踪您创建的内容,并且只“询问”您已经知道的小部件(并且您已经知道“真实”类型)。
如果您真的想要跟踪存在哪些小部件,您有两个主要选项。第一种是在创建小部件时将条目记录到ScriptDb中,然后再查找它们。像这样:
function doGet() {
var app = UiApp.createApplication();
var db = ScriptDb.getMyDb();
// You'd need to clear out old entries here... ignoring that for now
app.add(app.createButton().setId('foo')
.addClickHandler(app.createServerHandler("clicked")));
db.save({id: 'foo', type: 'button'});
app.add(app.createButton().setId('bar'));
db.save({id: 'bar', type: 'button'});
return app
}
然后在处理程序中,您可以查找其中的内容:
function clicked() {
var db = ScriptDb.getMyDb();
var widgets = db.query({}); // all widgets
var button = db.query({type: 'button'}); // all buttons
var foo = db.query({id: 'foo'}); // widget with id foo
}
或者,您可以通过使用标记
在纯粹的UiApp中完成此操作function doGet() {
var app = UiApp.createApplication();
var root = app.createFlowPanel(); // need a root panel
// tag just needs to exist; value is irrelevant.
var button1 = app.createButton().setId('button1').setTag("");
var button2 = app.createButton().setId('button2').setTag("");
// Add root as a callback element to any server handler
// that needs to know if widgets exist
button1.addClickHandler(app.createServerHandler("clicked")
.addCallbackElement(root));
root.add(button1).add(button2);
app.add(root);
return app;
}
function clicked(e) {
throw "\n" +
"button1 " + (e.parameter["button1_tag"] === "") + "\n" +
"button2 " + (e.parameter["button2_tag"] === "") + "\n" +
"button3 " + (e.parameter["button3_tag"] === "");
}
这将抛出:
button1 true
button2 true
button3 false
因为按钮1和2存在但3不存在。您可以通过在标记中存储类型来获得更好的功能,但这足以检查小部件是否存在。它的工作原理是因为根的所有子节点都被添加为回调元素,并且所有回调元素的标签都与处理程序一起发送。请注意,这听起来和听起来一样昂贵,对于具有大量小部件的应用程序可能会影响性能,尽管在许多情况下它可能都可以,特别是如果您只将root作为回调元素添加到实际需要验证的处理程序任意小部件的存在。
答案 1 :(得分:3)
我的初始解决方案是错误的,因为它返回false存在的控件。
基于Corey的答案,解决方案是添加setTag(“”)方法,现在可以使用代码了。它仅适用于事件处理程序,因为它使用标记。
function doGet() {
var app = UiApp.createApplication();
var btn01 = app.createButton("control01").setId("control01").setTag("");
var btn02 = app.createButton("control02").setId("control02").setTag("");
var handler = app.createServerHandler("clicked");
handler.addCallbackElement(btn01);
handler.addCallbackElement(btn02);
btn01.addClickHandler(handler);
btn02.addClickHandler(handler);
app.add(btn01);
app.add(btn02);
return app;
}
function clicked(e) {
var app = UiApp.getActiveApplication();
app.add(app.createLabel("control01 - " + controlExists(e, "control01")));
app.add(app.createLabel("control02 - " + controlExists(e, "control02")));
app.add(app.createLabel("fake - " + controlExists(e, "fake")));
return app;
}
function controlExists(e, controlName) {
return e.parameter[controlName + "_tag"] != null;
}