这只会在您创建小部件的同一执行中起作用,而不是在您检索小部件的后续事件处理程序中起作用,因为在这种情况下,无论它是否存在,一切都是 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
because buttons 1 and 2 exist but 3 doesn't. You can get fancier by storing the type in the tag, but this suffices to check for widget existence. It works because all children of the root get added as callback elements, and the tags for all callback elements are sent up with the handler. Note that this is as expensive as it sounds and for an app with a huge amount of widgets could potentially impact performance, although it's probably ok in many cases especially if you only add the root as a callback element to handlers that actually need to verify the existence of arbitrary widgets.