4

ID が存在しない場合でも、メソッドUiInstance.getElementById(ID)は常にオブジェクトを返します。GenericWidget

返されたオブジェクトがアプリに存在しないことを確認する方法、または 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 と組み合わせて使用​​します。

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 は、ブラウザー内のウィジェットへの一種の「ポインター」です。ブラウザとスクリプト間のデータ転送と待ち時間を短縮するために、作成したウィジェットを追跡しません (そうしないと、すべてのイベント ハンドラーに存在するウィジェットの長いリストを送信する必要があります)。作成したものを追跡し、既に存在することがわかっている (そして「実際の」タイプを既に知っている) ウィジェットのみを「要求」することになっています。

どのウィジェットが存在するかを本当に追跡したい場合は、主に 2 つのオプションがあります。1 つ目は、ウィジェットを作成するときにエントリを 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 は存在しないためです。タイプをタグに格納することでより洗練されたものにすることができますが、ウィジェットの存在を確認するにはこれで十分です。ルートのすべての子がコールバック要素として追加され、すべてのコールバック要素のタグがハンドラーで送信されるため、これが機能します。これは見た目と同じくらい高価であり、膨大な数のウィジェットを含むアプリの場合、パフォーマンスに影響を与える可能性があることに注意してください。ただし、実際に任意のウィジェットの存在。

于 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 に答える