4

方法UiInstance.getElementById(ID)总是返回GenericWidget对象,即使 ID 不存在。

有什么方法可以找出我的应用程序中不存在返回的对象,或者检查 UI 是否包含具有给定 ID 的对象?


使用 GUI builder 创建的 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 答案结合使用。

4

2 回答 2

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

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.

于 2012-10-04T13:41:22.117 回答
3

我最初的解决方案是错误的,因为它返回错误的存在控件。

根据 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;
}
于 2012-10-04T08:13:06.170 回答