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